chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:17:40 +08:00
commit f1825c8ceb
10096 changed files with 2364182 additions and 0 deletions
@@ -0,0 +1,153 @@
---
myst:
html_meta:
description: "How to configure and use AI coding agents like Claude Code on the Ray codebase, including the repository's shared CLAUDE.md instructions, rules, skills, and personal environment setup. Read this to work effectively with AI coding agents when developing Ray."
---
(agent-development)=
# Using agents for development
AI coding agents can accelerate development on the Ray codebase. This guide covers how the Ray project is configured for agent-assisted development and how to set up your local environment.
```{contents}
:local:
:backlinks: none
```
(claude-code-setup)=
## Claude Code
[Claude Code](https://code.claude.com) is an AI coding assistant that understands the Ray codebase through a hierarchy of instruction files, rules, and skills. For installation instructions, see the [official documentation](https://code.claude.com/docs).
### Project configuration
The Ray repository includes shared Claude Code configuration that is version-controlled:
- `.claude/CLAUDE.md`: root instructions loaded in every session
- `<library>/.claude/CLAUDE.md`: library-specific instructions loaded on-demand (for example, `python/ray/data/.claude/CLAUDE.md`)
- `.claude/rules/`: coding rules scoped by file type
- `.claude/skills/`: reusable workflows (rebuild, lint, fetch CI logs)
- `.claude/agents/`: project-specific subagents
Personal configuration lives in files that are **not** version-controlled:
- `CLAUDE.local.md`: your environment-specific instructions
- `.claude/settings.local.json`: your personal permission overrides
### Personal setup
After installing Claude Code, create a `CLAUDE.local.md` file in the repository root with your environment-specific configuration:
```markdown
## My Environment
- Python: /path/to/your/python
- Test runner: /path/to/your/python -m pytest
## My Git Setup
- origin = your-username/ray (fork)
- upstream = ray-project/ray (main repo)
## Preferences
- Add any personal preferences here
```
This file is gitignored and isn't committed.
### Cross-worktree setup
If you use multiple git worktrees, `CLAUDE.local.md` only exists in the worktree where you created it. To automatically symlink it from your main checkout whenever a new worktree is created, set up a `post-checkout` git hook:
1. From your main Ray checkout (not a worktree), create the hook file at `$(git rev-parse --git-common-dir)/hooks/post-checkout` with the following contents:
```bash
#!/bin/bash
# Auto-symlink CLAUDE.local.md into new worktrees.
MAIN_REPO="$(git rev-parse --git-common-dir)/.."
MAIN_LOCAL_MD="$(cd "$MAIN_REPO" && pwd)/CLAUDE.local.md"
if [ -f "$MAIN_LOCAL_MD" ] && [ ! -e "CLAUDE.local.md" ]; then
ln -s "$MAIN_LOCAL_MD" CLAUDE.local.md
fi
```
2. Make it executable:
```bash
chmod +x "$(git rev-parse --git-common-dir)/hooks/post-checkout"
```
3. The hook fires automatically when you create a new worktree with `git worktree add`. For existing worktrees, run the symlink manually:
```bash
ln -s /path/to/ray/CLAUDE.local.md CLAUDE.local.md
```
### Buildkite token setup
The `/fetch-buildkite-logs` skill requires a Buildkite API token to fetch CI logs.
1. Go to <https://buildkite.com/user/api-access-tokens>
2. Create a new token with these scopes:
- `read_builds`
- `read_build_logs`
3. Add it to your shell profile:
```bash
# Add to ~/.bashrc or ~/.zshrc
export BUILDKITE_API_TOKEN="your-token-here"
```
4. Reload your shell: `source ~/.bashrc`
### Available skills
Shared skills available in every session:
- `/rebuild`: guided Ray rebuild based on what files changed
- `/lint`: run linting and formatting checks
- `/fetch-buildkite-logs`: fetch and analyze Buildkite CI logs
### Adding team rules
Each Ray library has a `.claude/rules/` directory where teams can add coding rules that apply when working on their files. To add a new rule:
1. Create a `.md` file in your library's rules directory, for example, `python/ray/data/.claude/rules/data-conventions.md`
2. Add a `paths` frontmatter to scope it to your files:
```markdown
---
paths:
- "python/ray/data/**/*.py"
---
- Use logical operators from ray.data._internal.logical.operators
- Prefer streaming execution over batch where possible
```
Rules without `paths` frontmatter load unconditionally in every session. See the `README.md` in each rules directory for examples.
### Adding team skills
Skills are reusable workflows that load on-demand when invoked with `/<skill-name>`. To add a new skill:
1. Create a directory under your library's `.claude/skills/`, for example, `python/ray/data/.claude/skills/debug-data/`
2. Add a `SKILL.md` file with frontmatter:
```markdown
---
name: debug-data
description: Debug Ray Data pipeline issues
---
# Debug Data Pipeline
## Steps
1. Check the Data execution plan...
2. Look for common issues...
```
Skills in a library's `.claude/skills/` directory are discovered when working in that library. Shared skills in `.claude/skills/` are available everywhere.
+83
View File
@@ -0,0 +1,83 @@
---
myst:
html_meta:
description: "Ray's policies for documenting, promoting, demoting, and deprecating APIs across exposure levels, including the required annotations and deprecation timelines. Consult this when adding, changing, or removing a public Ray API."
---
(api-policy)=
# API policy
Ray APIs refer to classes, class methods, or functions. When we declare an API, we promise our users that they can use these APIs to develop their applications without worrying about changes to these interfaces between different Ray releases. Declaring or deprecating an API has a significant impact on the community. This document proposes simple policies to hold Ray contributors accountable to these promises and manage user expectations.
For API exposure levels, see {ref}`API Stability <api-stability>`.
## API documentation policy
Documentation is one of the main channels through which we expose our APIs to users. If we provide incorrect information, it can significantly impact the reliability and maintainability of our users' applications. Based on the API exposure level, here is the policy to ensure the accuracy of our information.
The API reference is generated from your source code, so how you write a public API affects the docs build directly. Before adding or changing one, see {ref}`how the docs build renders your API signatures <api-ref-build-behavior>` for the dependency-mocking and cross-linking behaviors you need to account for.
```{list-table} API Documentation Policy
:widths: 20 16 16 16 16 16
:header-rows: 1
* - Policy/Exposure Level
- Stable Public API
- Beta Public API
- Alpha Public API
- Deprecated
- Developer API
* - Must this API be documented?
- Yes
- Yes
- Yes
- Yes
- Up to the developers
* - Must a method be annotated with one of the API annotations (PublicAPI, DeveloperAPI or Deprecated)?
- Yes
- Yes
- Yes
- Yes
- No. The absence of annotations implies the Developer API level by default.
* - Can this API be private (either inside the _internal module or has an underscore prefix)?
- No
- No
- No
- No
- No
```
## API lifecycle policy
Users have high expectations for certain exposure levels, so we need to be cautious when moving APIs between different levels. Here is the policy for managing the API exposure lifecycle.
```{list-table} API Lifecycle Policy
:widths: 20 16 16 16 16 16
:header-rows: 1
* - Policy/Exposure Level
- Stable Public API
- Beta Public API
- Alpha Public API
- Deprecated API
- Developer API
* - Can this API be promoted to a higher level without any warnings or heads-up to users?
- Yes
- Yes
- Yes
- No
- Yes
* - Can this API be demoted to a lower level? If so then how?
- Can be demoted to Deprecated only. The API should emit warning messages and a deadline for deprecations in **six months (or +25 Ray minor versions)**.
- Can be demoted to Deprecated only. The API should emit warning messages and a deadline for deprecations in **three months (or +12 Ray minor versions)**.
- Users must allow for and expect breaking changes in alpha components, and must have no expectations of stability.
- Yes
- No annotations mean it is a developer API by default
* - Can you remove or change this API's parameters?
- Yes. The API should emit warning messages and you must set a deadline for the end-of-life of the original version that is **six months or +25 Ray minor versions**. During the transition period, you must support both the new and old parameters.
- Yes. The API should emit warning messages and you must set a deadline for the change in **three months or +12 Ray minor versions**. During the transition period, you must support both the new and old parameters.
- Users must allow for and expect breaking changes in alpha components, and must have no expectations of stability.
- No
- Yes
```
+38
View File
@@ -0,0 +1,38 @@
---
myst:
html_meta:
description: "Explains the continuous integration workflow on Ray pull requests, including the microcheck default test set, how to add tests to it, and the full suite that runs at merge time. Read this to understand which tests run on your PR and how to trigger more."
---
# CI testing workflow on PRs
This guide helps contributors understand the continuous integration (CI) workflow on a PR. Here, CI stands for automated testing of the codebase on the PR.
## `microcheck`: default tests on your PR
With every commit on your PR, by default, we'll run a set of tests called `microcheck`.
These tests are designed to be 90% accurate at catching bugs on your PR while running only 10% of the full test suite. As a result, microcheck typically finishes twice as fast and at half the cost of the full test suite. Some notable features of microcheck are:
* If a new test is added or an existing test is modified in a pull request, microcheck ensures these tests are included.
* You can manually add more tests to microcheck by including the following line in the body of your git commit message: `@microcheck TEST_TARGET01 TEST_TARGET02 ....`. This line must be in the body of your message, starting from the second line or below (the first line is the commit message title). For example, here is how I manually add tests in my pull request:
```
// git command to add commit message
git commit -a -s
// content of the commit message
run other serve doc tests
@microcheck //doc:source/serve/doc_code/distilbert //doc:source/serve/doc_code/object_detection //doc:source/serve/doc_code/stable_diffusion
Signed-off-by: can <can@anyscale.com>
```
If microcheck passes, you'll see a green checkmark on your PR. If it fails, you'll see a red cross. In either case, you'll see a summary of the test run statuses in the GitHub UI.
## Additional tests at merge time
In this workflow, to merge your PR, click the **Enable auto-merge** button (or ask a committer to do so). This triggers additional test cases, and the PR merges automatically once they finish and pass.
Alternatively, you can add a `go` label to manually trigger the full test suite on your PR. Be mindful that this is less recommended, but we understand you know best about the needs of your PR. We anticipate this being rarely needed, but if you require it constantly, please let us know. We're continuously improving the effectiveness of microcheck.
Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

+86
View File
@@ -0,0 +1,86 @@
---
myst:
html_meta:
description: "Debugging guide for Ray contributors, covering how to launch Ray processes under gdb, valgrind, and profilers using RAY_{PROCESS_NAME}_{DEBUGGER} environment variables. Use this to debug crashing or misbehaving Ray core processes."
---
# Debugging for Ray developers
This debugging guide is for contributors to the Ray project.
## Starting processes in a debugger
When processes are crashing, it's often useful to start them in a debugger. You can start Ray processes in any of the following:
- valgrind
- the valgrind profiler
- the perftools profiler
- gdb
- tmux
To use any of these tools, make sure you have them installed on your machine first. Note that `gdb` and `valgrind` on macOS are known to have issues. Then you can launch a subset of Ray processes by adding the environment variable `RAY_{PROCESS_NAME}_{DEBUGGER}=1`. For instance, to start the raylet in `valgrind`, set the environment variable `RAY_RAYLET_VALGRIND=1`.
To start a process in `gdb`, you must also start it in `tmux`. So to start the raylet in `gdb`, start your Python script with the following:
```bash
RAY_RAYLET_GDB=1 RAY_RAYLET_TMUX=1 python
```
You can then list the `tmux` sessions with `tmux ls` and attach to the appropriate one.
You can also get a core dump of the `raylet` process, which is especially useful when filing [issues](https://github.com/ray-project/ray/issues). The process to obtain a core dump is OS-specific, but usually involves running `ulimit -c unlimited` before starting Ray so core dump files can be written.
(backend-logging)=
## Backend logging
The `raylet` process logs detailed information about events such as task execution and object transfers between nodes. To set the logging level at runtime, you can set the `RAY_BACKEND_LOG_LEVEL` environment variable before starting Ray. For example:
```shell
export RAY_BACKEND_LOG_LEVEL=debug
ray start
```
This prints any `RAY_LOG(DEBUG)` lines in the source code to the `raylet.err` file, which you can find in {ref}`temp-dir-log-files`. If it worked, the first line in `raylet.err` should be:
```shell
logging.cc:270: Set ray log level from environment variable RAY_BACKEND_LOG_LEVEL to -1
```
(-1 is defined as RayLogLevel::DEBUG in logging.h.)
```{literalinclude} /../../src/ray/util/logging.h
:language: C
:lines: 113,120
```
## Backend event stats
The `raylet` process also periodically dumps event stats to `debug_state.txt` and its log file if the `RAY_event_stats=1` environment variable is set. To alter the interval at which Ray writes stats to log files, you can set `RAY_event_stats_print_interval_ms`.
Event stats include ASIO event handlers, periodic timers, and RPC handlers. Here is a sample of what the event stats look like:
```shell
Event stats:
Global stats: 739128 total (27 active)
Queueing time: mean = 47.402 ms, max = 1372.219 s, min = -0.000 s, total = 35035.892 s
Execution time: mean = 36.943 us, total = 27.306 s
Handler stats:
ClientConnection.async_read.ReadBufferAsync - 241173 total (19 active), CPU time: mean = 9.999 us, total = 2.411 s
ObjectManager.ObjectAdded - 61215 total (0 active), CPU time: mean = 43.953 us, total = 2.691 s
CoreWorkerService.grpc_client.AddObjectLocationOwner - 61204 total (0 active), CPU time: mean = 3.860 us, total = 236.231 ms
CoreWorkerService.grpc_client.GetObjectLocationsOwner - 51333 total (0 active), CPU time: mean = 25.166 us, total = 1.292 s
ObjectManager.ObjectDeleted - 43188 total (0 active), CPU time: mean = 26.017 us, total = 1.124 s
CoreWorkerService.grpc_client.RemoveObjectLocationOwner - 43177 total (0 active), CPU time: mean = 2.368 us, total = 102.252 ms
NodeManagerService.grpc_server.PinObjectIDs - 40000 total (0 active), CPU time: mean = 194.860 us, total = 7.794 s
```
## Callback latency injection
Sometimes bugs are caused by RPC issues. For example, the delay of some requests can cause the system to deadlock. To debug and reproduce this kind of issue, we need a way to inject latency into the RPC request. To enable this, use `RAY_testing_asio_delay_us`. To delay the callback of some RPC requests, use this variable. For example:
```shell
RAY_testing_asio_delay_us="NodeManagerService.grpc_client.PrepareBundleResources=2000000:2000000" ray start --head
```
The syntax for this is `RAY_testing_asio_delay_us="method1=min_us:max_us,method2=min_us:max_us"`. Entries are comma-separated. The special method `*` means all methods. It has a lower priority than other entries.
+479
View File
@@ -0,0 +1,479 @@
---
myst:
html_meta:
description: "Step-by-step instructions for building Ray from source, including Python-only fast-loop development, full C++ editable installs, manylinux wheels, and Docker images. Use this to set up a development environment for making and testing changes to Ray."
---
(building-ray)=
# Building Ray from source
To contribute to the Ray repository, follow these instructions to build from the latest master branch.
Depending on your goal, you may not need all sections on this page:
- **Python-only development (fast loop, no C++)**: edit Python files without compiling C++ (see {ref}`python-develop`).
- **Build Ray with C++**: choose one:
- **Distributable manylinux wheel**: uses a manylinux build container to produce a `.whl` file for installation on a cluster, for testing the packaged artifact locally, or for sharing (see {ref}`build-distributable-wheel`).
- **Ray image**: build a nightly-style `rayproject/ray` or `rayproject/ray-llm` image (see {ref}`build-ray-image`).
- **Full source build (editable install)**: make C++ changes or build all of Ray (see {ref}`full-source-build`).
```{contents}
:local:
:backlinks: none
```
## Setup
(fork-ray-repo)=
### Fork the Ray repository
Forking an open source repository is a best practice when contributing. You can make and test changes without affecting the original project, which keeps collaboration clean and organized. You can propose changes by submitting a pull request to the main project's repository.
1. Navigate to the [Ray GitHub repository](https://github.com/ray-project/ray).
2. Follow these [GitHub instructions](https://docs.github.com/en/get-started/quickstart/fork-a-repo), and do the following:
1. [Fork the repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo#forking-a-repository) using your preferred method.
2. [Clone](https://docs.github.com/en/get-started/quickstart/fork-a-repo#cloning-your-forked-repository) to your local machine.
3. [Connect your repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo#configuring-git-to-sync-your-fork-with-the-upstream-repository) to the upstream (main project) Ray repo to sync changes.
(prepare-venv)=
### Prepare a Python virtual environment
Skip this section if you're building a {ref}`distributable wheel <build-distributable-wheel>` or a {ref}`Ray image <build-ray-image>`.
Create a virtual environment to prevent version conflicts and to develop with an isolated, project-specific Python setup.
::::{tab-set}
:::{tab-item} conda
Set up a `conda` environment named `myenv`:
```shell
conda create -c conda-forge python=3.10 -n myenv
```
Activate your virtual environment to tell the shell or terminal to use this particular Python:
```shell
conda activate myenv
```
You need to activate the virtual environment every time you start a new shell or terminal to work on Ray.
:::
:::{tab-item} venv
Use Python's integrated `venv` module to create a virtual environment called `myenv` in the current directory:
```shell
python -m venv myenv
```
This contains a directory with all the packages used by the local Python of your project. You only need to do this step once.
Activate your virtual environment to tell the shell or terminal to use this particular Python:
```shell
source myenv/bin/activate
```
You need to activate the virtual environment every time you start a new shell or terminal to work on Ray.
Creating a new virtual environment can come with older versions of `pip` and `wheel`. To avoid problems when you install packages, use the module `pip` to install the latest version of `pip` (itself) and `wheel`:
```shell
python -m pip install --upgrade pip wheel
```
:::
::::
(python-develop)=
## Building Ray (Python only)
:::{note}
Unless otherwise stated, directory and file paths are relative to the project root directory.
:::
RLlib, Tune, Autoscaler, and most Python files don't require you to build and compile Ray. Follow these instructions to develop Ray's Python files locally without building Ray.
1. Make sure you have a clone of Ray's git repository (see {ref}`fork-ray-repo`).
2. Make sure you activate the Python (virtual) environment (see {ref}`prepare-venv`).
3. Pip install the **latest Ray wheels**. See {ref}`install-nightlies` for instructions.
```shell
# For example, for Python 3.10:
pip install -U https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-3.0.0.dev0-cp310-cp310-manylinux2014_x86_64.whl
```
4. Replace Python files in the installed package with your local editable copy. Use the script `python python/ray/setup-dev.py` to do this. The script removes the `ray/tune`, `ray/rllib`, `ray/autoscaler` directories (among others) bundled with the `ray` pip package, replacing them with links to your local code. This way, changing files in your git clone directly affects the behavior of your installed Ray.
```shell
# This replaces `<package path>/site-packages/ray/<package>`
# with your local `ray/python/ray/<package>`.
python python/ray/setup-dev.py
```
You can optionally skip creating symbolic links for specific directories:
```shell
# This links all folders except "_private" and "dashboard" without user prompt.
python python/ray/setup-dev.py -y --skip _private dashboard
```
(python-develop-uninstall)=
:::{warning}
Don't run `pip uninstall ray` or `pip install -U` (for Ray or Ray wheels) if setting up your environment this way. To uninstall or upgrade, first `rm -rf` the pip-installation site (usually a directory at the `site-packages/ray` location), then do a pip reinstall (see the command above), and finally run the `setup-dev.py` script again.
:::
```shell
# To uninstall, delete the symlinks first.
rm -rf <package path>/site-packages/ray # Path will be in the output of `setup-dev.py`.
pip uninstall ray # or `pip install -U <wheel>`
```
(build-distributable-wheel)=
## Building distributable manylinux wheels
:::{dropdown} Setup
:open:
Before you begin, make sure you have:
- A clone of the Ray repository (see {ref}`fork-ray-repo`)
- [uv](https://docs.astral.sh/uv/) installed
- [Docker](https://docs.docker.com/get-docker/) installed
:::
To build a distributable manylinux `.whl`, use the `build-wheel.sh` script at the repository root.
```bash
# Build a manylinux wheel for the host architecture:
./build-wheel.sh 3.12
# Specify a custom output directory:
./build-wheel.sh 3.12 ./dist
```
Run `./build-wheel.sh` without arguments to see supported Python versions and options. Regardless of host OS, the output is always a manylinux wheel (the same format used by CI and PyPI). Supported build hosts are Linux x86_64, Linux aarch64, and macOS ARM64.
See `python/README-building-wheels.md` for additional options, including building manylinux wheels directly with Docker.
(build-ray-image)=
## Building Ray images
:::{dropdown} Setup
:open:
Before you begin, make sure you have:
- A clone of the Ray repository (see {ref}`fork-ray-repo`)
- [uv](https://docs.astral.sh/uv/) installed
- [Docker](https://docs.docker.com/get-docker/) installed
:::
To build a Ray image, use the `build-image.sh` script at the repository root.
```bash
# Build the default Ray image:
./build-image.sh ray
# Build with a specific Python version:
./build-image.sh ray -p 3.12
# Build a GPU image:
./build-image.sh ray --platform cu12.8.1-cudnn
```
Run `./build-image.sh --help` to see available image types, Python versions, and platform variants.
(full-source-build)=
## Full source build
:::{tip}
If you already followed the instructions in {ref}`python-develop` and want to switch to the full build, first uninstall Ray (see {ref}`uninstallation steps <python-develop-uninstall>`).
:::
### Preparing to build Ray on Linux
:::{tip}
If you're only editing Tune, RLlib, or Autoscaler files, follow {ref}`python-develop` instead to avoid long build times.
:::
To build Ray on Ubuntu, run the following commands:
```bash
sudo apt-get update
sudo apt-get install -y build-essential curl clang-12 pkg-config psmisc unzip
# Install Bazelisk.
ci/env/install-bazel.sh
# Install node version manager and node 14
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install 14
nvm use 14
```
The `install-bazel.sh` script installs `bazelisk`. Note that `bazel` is installed at `$HOME/bin/bazel`. Make sure it's on your `PATH`. If you prefer to use `bazel` directly, only version `7.5.0` is supported.
### Preparing to build Ray on macOS
If you have grpc or protobuf installed, remove them first for a smooth build: `brew uninstall grpc`, `brew uninstall protobuf`. If the build fails with `No such file or directory` errors, clean previous builds with `brew uninstall binutils` and `bazel clean --expunge`.
To build Ray on macOS, first install these dependencies:
```bash
brew update
brew install wget
# Install Bazel.
ci/env/install-bazel.sh
```
### Building Ray on Linux and macOS (full)
Make sure you have a local clone of Ray's git repository (see {ref}`fork-ray-repo`). You also need to install [NodeJS](https://nodejs.org) to build the dashboard.
Go to the project directory, for example:
```shell
cd ray
```
Build the dashboard. From inside your local Ray project directory, go to the dashboard client directory:
```bash
cd python/ray/dashboard/client
```
Install the dependencies and build the dashboard:
```bash
npm ci
npm run build
```
Move back to the top-level Ray directory:
```shell
cd -
```
Now let's build Ray for Python. Make sure you activate any Python virtual (or conda) environment (see {ref}`prepare-venv`).
Go to the `python/` directory inside the Ray project directory and install the project with `pip`:
```bash
# Install Ray.
cd python/
# Install required dependencies.
pip install -r requirements.txt
# You may need to set the following two env vars if you have a macOS ARM64(M1) platform.
# See https://github.com/grpc/grpc/issues/25082 for more details.
# export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1
# export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1
pip install -e . --verbose # Add --user if you see a permission denied error.
```
The `-e` means "editable", so changes you make to files in the Ray directory take effect without reinstalling the package.
:::{warning}
Don't run `python setup.py install`. Python copies files from the Ray directory to a packages directory (`/lib/python3.6/site-packages/ray`), so changes you make to files in the Ray directory won't have any effect.
:::
If your machine runs out of memory during the build, add the following to `~/.bazelrc`:
> ```shell
> build --local_resources=memory=HOST_RAM*.5 --local_resources=cpu=4
> ```
>
> The `build --disk_cache=~/bazel-cache` option can also speed up repeated builds.
If you run into an error building protobuf, switching from miniforge to anaconda might help.
### Building Ray on Windows (full)
**Requirements**
The following links were accurate at the time of writing. If a URL has changed, search the organization's site.
- Bazel 7.5.0 (<https://github.com/bazelbuild/bazel/releases/tag/7.5.0>)
- Microsoft Visual Studio 2019 (or Microsoft Build Tools 2019 - <https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019>)
- JDK 15 (<https://www.oracle.com/java/technologies/javase-jdk15-downloads.html>)
- Miniforge 3 (<https://github.com/conda-forge/miniforge/blob/main/README.md>)
- git for Windows, version 2.31.1 or later (<https://git-scm.com/download/win>)
You can also use the included script to install Bazel:
```bash
# Install Bazel.
ray/ci/env/install-bazel.sh
# (Windows users: please manually place Bazel in your PATH, and point
# BAZEL_SH to MSYS2's Bash: ``set BAZEL_SH=C:\Program Files\Git\bin\bash.exe``)
```
**Steps**
1. Enable Developer mode on Windows 10 systems. This is necessary so git can create symlinks.
1. Open the Settings app.
2. Go to "Update & Security".
3. Go to "For Developers" in the left pane.
4. Turn on "Developer mode".
2. Add the following Miniforge subdirectories to PATH. If Miniforge was installed for all users, the following paths are correct. If Miniforge is installed for a single user, adjust the paths accordingly.
- `C:\ProgramData\miniforge3`
- `C:\ProgramData\miniforge3\Scripts`
- `C:\ProgramData\miniforge3\Library\bin`
3. Define an environment variable `BAZEL_SH` to point to `bash.exe`. If git for Windows was installed for all users, bash's path should be `C:\Program Files\Git\bin\bash.exe`. If git was installed for a single user, adjust the path accordingly.
4. Install Bazel 7.5.0. Go to the Bazel 7.5.0 release page and download `bazel-7.5.0-windows-x86_64.exe`. Copy the exe into the directory of your choice. Define an environment variable `BAZEL_PATH` to the full exe path (example: `set BAZEL_PATH=C:\bazel\bazel.exe`). Also add the Bazel directory to `PATH` (example: `set PATH=%PATH%;C:\bazel`).
5. Download the Ray source code and build it.
```shell
# cd to the directory under which the ray source tree will be downloaded.
git clone -c core.symlinks=true https://github.com/ray-project/ray.git
cd ray\python
pip install -e . --verbose
```
## Advanced build options
### Environment variables that influence builds
You can tweak the build with the following environment variables (when running `pip install -e .` or `python setup.py install`):
- `RAY_BUILD_CORE`: If set and equal to `1`, Ray builds the core parts. Defaults to `1`.
- `RAY_INSTALL_JAVA`: If set and equal to `1`, Ray runs extra build steps to build Java portions of the codebase.
- `RAY_INSTALL_CPP`: If set and equal to `1`, Ray installs `ray-cpp`.
- `RAY_BUILD_REDIS`: If set and equal to `1`, Ray builds or fetches Redis binaries. These binaries are only used for testing. Defaults to `1`.
- `RAY_DISABLE_EXTRA_CPP`: If set and equal to `1`, a regular (non-`cpp`) build won't provide some `cpp` interfaces.
- `SKIP_BAZEL_BUILD`: If set and equal to `1`, Ray skips all Bazel build steps.
- `SKIP_THIRDPARTY_INSTALL_CONDA_FORGE`: If set, setup skips installation of third-party packages required for build. This is active on conda-forge where pip isn't used to create a build environment.
- `RAY_DEBUG_BUILD`: Can be set to `debug`, `asan`, or `tsan`. Ray ignores any other value.
- `BAZEL_ARGS`: If set, pass a space-separated set of arguments to Bazel. This can be useful for restricting resource usage during builds, for example. See [the Bazel user manual](https://bazel.build/docs/user-manual) for more information about valid arguments.
- `IS_AUTOMATED_BUILD`: Used in conda-forge CI to tweak the build for the managed CI machines.
- `SRC_DIR`: Can be set to the root of the source checkout, defaults to `None`, which is `cwd()`.
- `BAZEL_SH`: Used on Windows to find `bash.exe`. See below.
- `BAZEL_PATH`: Used on Windows to find `bazel.exe`. See below.
- `MINGW_DIR`: Used on Windows to find `bazel.exe` if not found in `BAZEL_PATH`.
### Fast, debug, and optimized builds
By default, Ray builds with optimizations, which can take a long time and interfere with debugging. To perform fast, debug, or optimized builds, run the following (via `-c` with `fastbuild`, `dbg`, or `opt`, respectively):
```shell
bazel run -c fastbuild //:gen_ray_pkg
```
This rebuilds Ray with the appropriate options (which might take a while). If you need to build all targets, use `bazel build //:all` instead of `bazel run //:gen_ray_pkg`.
To make this change permanent, you can add an option such as the following line to your user-level `~/.bazelrc` file (not to be confused with the workspace-level `.bazelrc` file):
```shell
build --compilation_mode=fastbuild
```
If you do so, remember to revert this change, unless you want it to affect all of your development in the future.
Using `dbg` instead of `fastbuild` generates more debug information, which can make it easier to debug with a debugger such as `gdb`.
### Using a local repository for dependencies
If you'd like to build Ray with custom dependencies (for example, with a different version of Cython), you can modify your `.bzl` file as follows:
```python
http_archive(
name = "cython",
...,
) if False else native.new_local_repository(
name = "cython",
build_file = "bazel/BUILD.cython",
path = "../cython",
)
```
This replaces the existing `http_archive` rule with one that references a sibling of your Ray directory (named `cython`) using the build file provided in the Ray repository (`bazel/BUILD.cython`). If the dependency already has a Bazel build file in it, you can use `native.local_repository` instead, and omit `build_file`.
To test switching back to the original rule, change `False` to `True`.
## Development tooling
### Installing additional dependencies for development
Install dependencies for the linter (`pre-commit`):
```shell
pip install -c python/requirements_compiled.txt pre-commit
pre-commit install
```
Install dependencies for running Ray unit tests under `python/ray/tests`:
```shell
pip install -c python/requirements_compiled.txt -r python/requirements/test-requirements.txt
```
Requirement files for running Ray Data and ML library tests are under `python/requirements/`.
### Pre-commit hooks
Ray uses pre-commit hooks with [the pre-commit Python package](https://pre-commit.com/). The `.pre-commit-config.yaml` file configures all the linting and formatting checks. To start using `pre-commit`:
```shell
pip install pre-commit
pre-commit install
```
This installs pre-commit into the current environment and enables pre-commit checks every time you commit new code changes with git. To temporarily skip pre-commit checks, use the `-n` or `--no-verify` flag when committing:
```shell
git commit -n
```
If you encounter any issues with `pre-commit`, [report an issue](https://github.com/ray-project/ray/issues/new?template=bug-report.yml).
## Building the docs
To learn more about building the docs, see {doc}`Contributing to the Ray documentation <docs>`.
## Troubleshooting
If importing Ray (`python3 -c "import ray"`) in your development clone results in this error:
```python
Traceback (most recent call last):
File "<string>", line 1, in <module>
File ".../ray/python/ray/__init__.py", line 63, in <module>
import ray._raylet # noqa: E402
File "python/ray/_raylet.pyx", line 98, in init ray._raylet
import ray.memory_monitor as memory_monitor
File ".../ray/python/ray/memory_monitor.py", line 9, in <module>
import psutil # noqa E402
File ".../ray/python/ray/thirdparty_files/psutil/__init__.py", line 159, in <module>
from . import _psosx as _psplatform
File ".../ray/python/ray/thirdparty_files/psutil/_psosx.py", line 15, in <module>
from . import _psutil_osx as cext
ImportError: cannot import name '_psutil_osx' from partially initialized module 'psutil' (most likely due to a circular import) (.../ray/python/ray/thirdparty_files/psutil/__init__.py)
```
Run the following commands:
```bash
rm -rf python/ray/thirdparty_files/
python3 -m pip install psutil
```
@@ -0,0 +1,8 @@
# example_module.py
# fmt: off
# __is_even_begin__
def is_even(x):
return (x % 2) == 0
# __is_even_end__
# fmt: on
+455
View File
@@ -0,0 +1,455 @@
---
myst:
html_meta:
description: "How to contribute to the Ray documentation: building the docs locally, the Google developer style guide enforced by Vale, and the conventions for writing and previewing pages. Use this when editing or adding Ray documentation."
---
# Contributing to the Ray documentation
There are many ways to contribute to the Ray documentation, and we're always looking for new contributors. Even if you want to fix a typo or expand a section, feel free to do so!
This document walks you through everything you need to do to get started.
## Editorial style
The Ray documentation follows a house style guide that covers voice, word choice, sentence structure, headings, lists, links, and formatting. Read it before you write or edit a page. See {ref}`documentation-style`.
The house guide builds on the [Google developer documentation style guide](https://developers.google.com/style), which is the fallback for anything the house guide doesn't cover. Vale enforces an automated subset of the Google guide in CI. For more information, see [How to use Vale](vale).
## Building the Ray documentation
If you want to contribute to the Ray documentation, you need a way to build it. Don't install Ray in the environment you plan to use to build documentation. The requirements for the docs build system are generally not compatible with those you need to run Ray itself.
Follow these instructions to build the documentation:
### Fork Ray
1. {ref}`Fork the Ray repository <fork-ray-repo>`.
2. {ref}`Clone the forked repository <fork-ray-repo>` to your local machine.
Next, go to the `ray/doc` directory:
```shell
cd ray/doc
```
### Install dependencies
If you haven't done so already, create a Python environment separate from the one you use to build and run Ray. Use Python 3.11 to match the version Read the Docs builds with. For example, if you're using `conda`:
```shell
conda create -n docs python=3.11
```
Next, activate the Python environment you're using (for example, venv or conda). With `conda`, this would be:
```shell
conda activate docs
```
Install the documentation dependencies with the following command:
```shell
pip install -r requirements-doc.lock.txt
```
Don't use `-U` in this step. `requirements-doc.lock.txt` is a lock file that pins the exact versions of all the required dependencies.
### Build documentation
Before building, clean your environment by running:
```shell
make clean
```
Choose from the following two options to build documentation locally:
- Incremental build
- Full build
#### 1. Incremental build with global cache and live rendering
To use this option, you can run:
```shell
make local
```
We recommend this option if you need to make frequent, small, uncomplicated changes such as editing text or adding content within existing files.
In this approach, Sphinx only builds the changes you made in your branch compared to your last pull from upstream master. The rest of the doc is cached with pre-built doc pages from your last commit from upstream. For every new commit pushed to Ray, CI builds all the documentation pages from that commit and stores them on S3 as cache.
The build first traces your commit tree to find the latest commit that CI already cached on S3. Once the build finds the commit, it fetches the corresponding cache from S3 and extracts it into the `doc/` directory. Simultaneously, CI tracks all the files that have changed from that commit to current `HEAD`, including any unstaged changes.
Sphinx then rebuilds only the pages that your changes affect, leaving the rest untouched from the cache.
When the build finishes, the doc page automatically opens in your browser. If you make a change in the `doc/` directory, Sphinx automatically rebuilds and reloads the page. Stop it with `Ctrl+C`.
For more complicated changes that involve adding or removing files, always use `make develop` first. Then use `make local` to iterate on the cache that `make develop` produces.
#### 2. Full build from scratch
In the full build option, Sphinx rebuilds all files in the `doc/` directory, ignoring all cache and saved environment. Because of this behavior, you get a clean build, but it's much slower.
```shell
make develop
```
Find the documentation build in the `_build` directory. After the build finishes, open the `_build/html/index.html` file in your browser. It's good practice to check the output of your build to make sure everything works as expected.
Before committing any changes, run the [linter](getting-involved.md#lint-and-formatting) with `pre-commit run` from the `doc` folder to make sure your changes are formatted correctly.
### Verify a Read the Docs-faithful build
`make local` and `make develop` are for fast iteration while you author. Before you push, verify your changes the way Read the Docs builds them, so you catch failures locally instead of waiting on a Read the Docs build:
```shell
make rtd-build
```
`make rtd-build` reproduces the full build Read the Docs runs from a fresh checkout, with `fail_on_warning` enabled, so any Sphinx warning fails the build exactly as it does on Read the Docs. It first runs a preflight check that your environment matches Read the Docs — the Python version Read the Docs builds with (3.11) and the dependency versions pinned in `requirements-doc.lock.txt` — and stops with an explanation if it finds drift. Run that check on its own at any time with:
```shell
make rtd-doctor
```
A full build matters most when you add, remove, or rename files. The incremental `make local` build reuses cached pages, so a rename that breaks a cross-reference in an otherwise-unchanged page can pass locally and only fail on Read the Docs. `make rtd-build` always does a full build, so it catches these.
If you intend to build on an environment that doesn't match Read the Docs, run `make rtd-build RTD_DOCTOR_ARGS=--warn-only` to downgrade the preflight check from an error to a warning.
### Code completion and other developer tooling
If you find yourself working with documentation often, you might find the [esbonio](https://github.com/swyddfa/esbonio) language server useful. Esbonio provides context-aware syntax completion, definitions, diagnostics, document links, and other information for RST documents. If you're unfamiliar with [language servers](https://en.wikipedia.org/wiki/Language_Server_Protocol), they're important pieces of a modern developer's toolkit. If you've used `pylance` or `python-lsp-server` before, you'll know how useful these tools can be.
Esbonio also provides a VS Code extension that includes a live preview. Install the `esbonio` VS Code extension to start using the tool:
![The esbonio extension in VS Code](esbonio.png)
As an example of Esbonio's autocompletion capabilities, you can type `..` to pull up an autocomplete menu for all RST directives:
![VS Code autocomplete menu showing RST directives](completion.png)
Esbonio also works with neovim. [See the lspconfig repository for installation instructions](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#esbonio).
## The basics of our build system
The Ray documentation is built with the [`sphinx`](https://www.sphinx-doc.org/) build system. We use the [PyData Sphinx Theme](https://pydata-sphinx-theme.readthedocs.io/en/stable/) for the documentation.
We use [`myst-parser`](https://myst-parser.readthedocs.io/en/latest/) so you can write Ray documentation in either Sphinx's native [reStructuredText (rST)](https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html) or [Markedly Structured Text (MyST)](https://myst-parser.readthedocs.io/en/latest/). You can convert the two formats to each other, so the choice is up to you. MyST is [common markdown compliant](https://myst-parser.readthedocs.io/en/latest/syntax/reference.html#commonmark-block-tokens). Most developers are familiar with `md` syntax, so if you intend to add a new document, we recommend starting from an `.md` file.
The Ray documentation also fully supports executable formats such as [Jupyter Notebooks](https://jupyter.org/). Many of our examples are notebooks with [MyST markdown cells](https://myst-nb.readthedocs.io/en/latest/index.html).
## What to contribute?
If you take Ray Tune as an example, you can see that our documentation consists of several types of documentation, all of which you can contribute to:
- [a project landing page](https://docs.ray.io/en/latest/tune/index.html),
- [a getting started guide](https://docs.ray.io/en/latest/tune/getting-started.html),
- [a key concepts page](https://docs.ray.io/en/latest/tune/key-concepts.html),
- [user guides for key features](https://docs.ray.io/en/latest/tune/tutorials/overview.html),
- [practical examples](https://docs.ray.io/en/latest/tune/examples/index.html),
- [a detailed FAQ](https://docs.ray.io/en/latest/tune/faq.html),
- [and API references](https://docs.ray.io/en/latest/tune/api/api.html).
This structure is reflected in the [Ray documentation source code](https://github.com/ray-project/ray/tree/master/doc/source/tune) as well, so you should have no problem finding what you're looking for. All other Ray projects share a similar structure, but depending on the project there might be minor differences.
Each type of documentation listed above has its own purpose, but ultimately our documentation comes down to _two types_ of documents:
- Markup documents, written in MyST or rST. If you don't have a lot of (executable) code to contribute or use more complex features such as [tabbed content blocks](https://docs.ray.io/en/latest/ray-core/walkthrough.html#starting-ray), this is the right choice. Most of the documents in Ray Tune are written in this way, for instance the [key concepts](https://github.com/ray-project/ray/blob/master/doc/source/tune/key-concepts.rst) or [API documentation](https://github.com/ray-project/ray/blob/master/doc/source/tune/api/api.rst).
- Notebooks, written in `.ipynb` format. All Tune examples are written as notebooks. These notebooks render in the browser like `.md` or `.rst` files, but have the added benefit that users can run the code themselves.
## Fixing typos and improving explanations
If you spot a typo in any document, or think an explanation isn't clear enough, consider opening a pull request. In this scenario, run the linter as described above and submit your pull request.
## Adding API references
We use [Sphinx's autodoc extension](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) to generate our API documentation from our source code. If we're missing a reference to a function or class, consider adding it to the document in question.
For example, here's how you can add a function or class reference using `autofunction` and `autoclass`:
```markdown
.. autofunction:: ray.tune.integration.docker.DockerSyncer
.. autoclass:: ray.tune.integration.keras.TuneReportCallback
```
The above snippet comes from the [Tune API documentation](https://github.com/ray-project/ray/blob/master/doc/source/tune/api/integration.rst), which you can look at for reference.
If you want to change the content of the API documentation, you must edit the function or class signatures directly in the source code. For example, in the above `autofunction` call, to change the API reference for `ray.tune.integration.docker.DockerSyncer`, you would [change the following source file](https://github.com/ray-project/ray/blob/7f1bacc7dc9caf6d0ec042e39499bbf1d9a7d065/python/ray/tune/integration/docker.py#L15-L38).
To show the usage of APIs, it's important to have small usage examples embedded in the API documentation. These should be self-contained and run out of the box, so a user can copy and paste them into a Python interpreter and play around with them. For example, if applicable, they should point to example data. Users often rely on these examples to build their applications. To learn more about writing examples, read [How to write code snippets](writing-code-snippets).
(api-ref-build-behavior)=
### How the docs build renders your API signatures
The API reference is generated from your source code: autodoc imports the module to read its signatures and docstrings. Two build behaviors affect what you write in code, even if you never build the docs yourself.
**Heavy dependencies are mocked, so keep your imports safe.** The docs build installs only a light dependency set, not Ray's full runtime. Heavy or optional libraries such as `torch`, `tensorflow`, and `pandas` are replaced by mock objects, listed in `autodoc_mock_imports` in `doc/source/conf.py`, so autodoc can import your module without importing those libraries. If your module imports a heavy dependency at import time and that library isn't mocked, the API-ref build fails. Note that Sphinx's autodoc sets `typing.TYPE_CHECKING` to `True` during the build to resolve type annotations, so imports guarded by `if TYPE_CHECKING:` will still be executed and can cause failures if not mocked. A mock can also stand in for an object incorrectly and abort the whole module import, which surfaces as a confusing, unrelated error. To avoid both, import heavy dependencies lazily inside the function or method that needs them rather than at module top level. If you add a public API that puts a new heavy dependency in a signature, add that library to `autodoc_mock_imports`.
**Type annotations link to external docs through intersphinx.** When a public signature is annotated with a type from an external library, such as `numpy.ndarray` or `torch.Tensor`, the build turns it into a link to that library's own documentation using the `intersphinx_mapping` in `doc/source/conf.py`. The link resolves only if the library is in that mapping. If you add a public API whose signature references a new external library and you want its types linked, add the library to `intersphinx_mapping` (and, per the point above, usually to `autodoc_mock_imports` too). Annotations that don't resolve render as plain text; they don't fail the build.
## Adding code to an `.rST` or `.md` file
Modifying text in an existing documentation file is easy, but you need to be careful when it comes to adding code. The reason is that we want to ensure every code snippet in our documentation is tested. This requires us to have a process for including and testing code snippets in documents. To learn how to write testable code snippets, read [How to write code snippets](writing-code-snippets).
```python
from ray import train
def objective(x, a, b): # Define an objective function.
return a * (x ** 0.5) + b
def trainable(config): # Pass a "config" dictionary into your trainable.
for x in range(20): # "Train" for 20 iterations and compute intermediate scores.
score = objective(x, config["a"], config["b"])
train.report({"score": score}) # Send the score to Tune.
```
This code is imported by `literalinclude` from a file called `doc_code/key_concepts.py`. Every Python file in the `doc_code` directory is automatically tested by our CI system, but make sure to run scripts that you change (or new scripts) locally first. You don't need to run the testing framework locally.
In rare situations, when you're adding _obvious_ pseudo-code to demonstrate a concept, it's OK to add it literally into your `.rst` or `.md` file, for example, using a `.. code-cell:: python` directive. But if your code is supposed to run, it needs to be tested.
## Creating a new document from scratch
Sometimes you might want to add a completely new document to the Ray documentation, such as a new user guide or a new example.
For this to work, you must add the new document explicitly to a parent document's toctree, which determines the structure of the Ray documentation. See [the Sphinx documentation](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-toctree) for more information.
Depending on the type of document you're adding, you might also have to make changes to an existing overview page that curates the list of documents in question. For instance, for Ray Tune each user guide is added to the [user guide overview page](https://docs.ray.io/en/latest/tune/tutorials/overview.html) as a panel, and the same goes for [all Tune examples](https://docs.ray.io/en/latest/tune/examples/index.html). Always check the structure of the Ray sub-project whose documentation you're working on to see how to integrate it within the existing structure. In some cases you may need to choose an image for the panel. Images are in `doc/source/images`.
## Creating a notebook example
To add a new executable example to the Ray documentation, you can start from our [MyST notebook template](https://github.com/ray-project/ray/blob/master/doc/source/_templates/template.md) or [Jupyter notebook template](https://github.com/ray-project/ray/blob/master/doc/source/_templates/template.ipynb). You could also download the document you're reading right now and start modifying it. Click the download button at the top of this page to get the `.ipynb` file. All the example notebooks in Ray Tune are automatically tested by our CI system, provided you place them in the [`examples` folder](https://github.com/ray-project/ray/tree/master/doc/source/tune/examples). If you have questions about how to test your notebook when contributing to other Ray sub-projects, ask in [the Ray community Slack](https://www.ray.io/join-slack) or directly on GitHub when opening your pull request.
To work from an existing example, look at the [Ray Tune Hyperopt example (`.ipynb`)](https://github.com/ray-project/ray/blob/master/doc/source/tune/examples/hyperopt_example.ipynb) or the [Ray Serve guide for text classification (`.md`)](https://github.com/ray-project/ray/blob/master/doc/source/serve/tutorials/text-classification.md). We recommend that you start with an `.md` file and convert it to an `.ipynb` notebook at the end of the process. We'll walk you through this process below.
What makes these notebooks different from other documents is that they combine code and text in one document, and you can launch them in the browser. We also make sure our CI system tests them before we add them to our documentation. To make this work, notebooks need to define a _kernel specification_ to tell a notebook server how to interpret and run the code. For instance, here's the kernel specification of a Python notebook:
```markdown
---
jupytext:
text_representation:
extension: .md
format_name: myst
kernelspec:
display_name: Python 3
language: python
name: python3
---
```
If you write a notebook in `.md` format, you need this YAML front matter at the top of the file. To add code to your notebook, you can use the `code-cell` directive. Here's an example:
````markdown
```python
import ray
import ray.rllib.agents.ppo as ppo
from ray import serve
def train_ppo_model():
trainer = ppo.PPOTrainer(
config={"framework": "torch", "num_workers": 0},
env="CartPole-v0",
)
# Train for one iteration
trainer.train()
trainer.save("/tmp/rllib_checkpoint")
return "/tmp/rllib_checkpoint/checkpoint_000001/checkpoint-1"
checkpoint_path = train_ppo_model()
```
````
Putting this markdown block into your document renders as follows in the browser:
```python
import ray
import ray.rllib.agents.ppo as ppo
from ray import serve
def train_ppo_model():
trainer = ppo.PPOTrainer(
config={"framework": "torch", "num_workers": 0},
env="CartPole-v0",
)
# Train for one iteration
trainer.train()
trainer.save("/tmp/rllib_checkpoint")
return "/tmp/rllib_checkpoint/checkpoint_000001/checkpoint-1"
checkpoint_path = train_ppo_model()
```
### Tags for your notebook
What makes this work is the `:tags: [hide-cell]` directive in the `code-cell`. The reason we suggest starting with `.md` files is that it's much easier to add tags to them, as you've seen. You can also add tags to `.ipynb` files, but you'll need to start a notebook server for that first, which you may not want to do to contribute a piece of documentation.
Apart from `hide-cell`, you also have `hide-input` and `hide-output` tags that hide the input and output of a cell. Also, if you need code that runs in the notebook but you don't want to show it in the documentation, you can use the `remove-cell`, `remove-input`, and `remove-output` tags in the same way.
### Reference section labels
[Reference section labels](https://jupyterbook.org/en/stable/content/references.html#reference-section-labels) are a way to link to specific parts of the documentation from within a notebook. Creating one inside a markdown cell is simple:
```markdown
(my-label)=
# The thing to label
```
Then, you can link it in .rst files with the following syntax:
```rst
See {ref}`the thing that I labeled <my-label>` for more information.
```
### Testing notebooks
Removing cells can be particularly interesting for compute-intensive notebooks. We want you to contribute notebooks that use _realistic_ values, not just toy examples. At the same time, we want our CI system to test our notebooks, and running them shouldn't take too long. To address this, use notebook cells with the parameters you want the users to see first:
````markdown
```{code-cell} python3
num_workers = 8
num_gpus = 2
```
````
which will render as follows in the browser:
```python
num_workers = 8
num_gpus = 2
```
But then in your notebook, you follow that up with a _removed_ cell that won't render, but has much smaller values and makes the notebook run faster:
````markdown
```{code-cell} python3
:tags: [remove-cell]
num_workers = 0
num_gpus = 0
```
````
### Converting markdown notebooks to ipynb
Once you're finished writing your example, you can convert it to an `.ipynb` notebook using `jupytext`:
```shell
jupytext your-example.md --to ipynb
```
In the same way, you can convert `.ipynb` notebooks to `.md` notebooks with `--to myst`. And if you want to convert your notebook to a Python file, for example, to test whether your whole script runs without errors, you can use `--to py` instead.
(vale)=
## How to use Vale
### What is Vale?
[Vale](https://vale.sh/) checks whether your writing adheres to the [Google developer documentation style guide](https://developers.google.com/style). It's only enforced on the Ray Data documentation.
Vale catches typos and grammatical errors. It also enforces stylistic rules such as "use contractions" and "use second person." For the full list of rules, see the [configuration in the Ray repository](https://github.com/ray-project/ray/tree/master/.vale/styles/Google).
### How do you run Vale?
#### How to use the VS Code extension
1. Install Vale. If you use macOS, use Homebrew.
```bash
brew install vale
```
Otherwise, use PyPI.
```bash
pip install vale
```
For more information on installation, see the [Vale documentation](https://vale.sh/docs/vale-cli/installation/).
2. Install the Vale VS Code extension by following these [installation instructions](https://marketplace.visualstudio.com/items?itemName=ChrisChinchilla.vale-vscode).
3. VS Code should show warnings in your code editor and in the "Problems" panel.
![Vale warnings in the VS Code Problems panel](../images/vale.png)
#### How to run Vale on the command line
1. Install Vale. If you use macOS, use Homebrew.
```bash
brew install vale
```
Otherwise, use PyPI.
```bash
pip install vale
```
For more information on installation, see the [Vale documentation](https://vale.sh/docs/vale-cli/installation/).
2. Run Vale in your terminal.
```bash
vale doc/source/data/overview.rst
```
3. Vale should show warnings in your terminal.
```
vale doc/source/data/overview.rst
doc/source/data/overview.rst
18:1 warning Try to avoid using Google.We
first-person plural like 'We'.
18:46 error Did you really mean Vale.Spelling
'distrbuted'?
24:10 suggestion In general, use active voice Google.Passive
instead of passive voice ('is
built').
28:14 warning Use 'doesn't' instead of 'does Google.Contractions
not'.
✖ 1 error, 2 warnings and 1 suggestion in 1 file.
```
### How to handle false Vale.Spelling errors
To add custom terminology, complete the following steps:
1. If it doesn't already exist, create a directory for your team in `.vale/styles/Vocab`. For example, `.vale/styles/Vocab/Data`.
2. If it doesn't already exist, create a text file named `accept.txt`. For example, `.vale/styles/Vocab/Data/accept.txt`.
3. Add your term to `accept.txt`. Vale accepts Regex.
For more information, see [Vocabularies](https://vale.sh/docs/topics/vocab/) in the Vale documentation.
### How to handle false Google.WordList errors
Vale errors if you use a word that isn't on [Google's word list](https://developers.google.com/style/word-list).
```
304:52 error Use 'select' instead of Google.WordList
'check'.
```
If you want to use the word anyway, modify the appropriate field in the [WordList configuration](https://github.com/ray-project/ray/blob/81c169bde2414fe4237f3d2f05fc76fccfd52dee/.vale/styles/Google/WordList.yml#L41).
## Troubleshooting
If you run into a problem building the docs, following these steps can help isolate or eliminate most issues:
1. **Clean out build artifacts.** Use `make clean` to clean out docs build artifacts in the working directory. Sphinx uses caching to avoid doing work, and this sometimes causes problems. This is particularly true if you build the docs, then `git pull origin master` to pull in recent changes, and then try to build docs again.
2. **Check your environment.** Use `pip list` to check the installed dependencies. Compare them to `doc/requirements-doc.txt`. The documentation build system doesn't have the same dependency requirements as Ray. You don't need to run ML models or execute code on distributed systems in order to build the docs. In fact, it's best to use a completely separate docs build environment from the environment you use to run Ray to avoid dependency conflicts. When installing requirements, do `pip install -r doc/requirements-doc.txt`. Don't use `-U` because you don't want to upgrade any dependencies during the installation. To check your environment against Read the Docs automatically, run `make rtd-doctor`, which compares your interpreter and the pinned docs dependencies to the versions Read the Docs uses and tells you what to fix.
3. **Match the Read the Docs Python version.** The docs build system doesn't keep the same dependency and Python version requirements as Ray. Read the Docs builds with the Python version pinned in `.readthedocs.yaml` (currently 3.11), so use that same version locally; building with a different version can surface or hide warnings that then behave differently on Read the Docs.
4. **Enable breakpoints in Sphinx.** Add `-P` to the `SPHINXOPTS` in `doc/Makefile` to tell `sphinx` to stop when it encounters a breakpoint, and remove `-j auto` to disable parallel builds. Now you can put breakpoints in the modules you're trying to import, or in `sphinx` code itself, which can help isolate stubborn build issues.
5. **[Incremental build] Side navigation bar doesn't reflect new pages.** If you're adding new pages, they should always show up in the side navigation bar on index pages. However, incremental builds with `make local` skip rebuilding many other pages, so Sphinx doesn't update the side navigation bar on those pages. To build docs with a correct side navigation bar on all pages, consider using `make develop`.
## Where to go from here?
There are many ways to contribute to Ray other than documentation. See {doc}`our contributor guide <getting-involved>` for more information.
Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

@@ -0,0 +1,209 @@
---
myst:
html_meta:
description: "How to run and test Ray's autoscaler locally without a real cluster, using RAY_FAKE_CLUSTER and the fake multi-node provider. Useful for autoscaler development or for debugging applications that depend on autoscaling behavior."
---
(fake-multinode)=
# Testing autoscaling locally
Testing autoscaling behavior is important for autoscaler development and for debugging applications that depend on autoscaler behavior. You can run the autoscaler locally, without launching a real cluster, using one of the following methods:
## Using `RAY_FAKE_CLUSTER=1 ray start`
Complete the following steps:
1. Navigate to the root directory of the Ray repo you have cloned locally.
2. Locate the [fake_multi_node/example.yaml](https://github.com/ray-project/ray/blob/master/python/ray/autoscaler/_private/fake_multi_node/example.yaml) example file and fill in the number of CPUs and GPUs the local machine has for the head node type config. The YAML follows the same format as cluster autoscaler configurations, but some fields are not supported.
3. Configure worker types and other autoscaling configs as desired in the YAML file.
4. Start the fake cluster locally:
```shell
$ ray stop --force
$ RAY_FAKE_CLUSTER=1 ray start \
--autoscaling-config=./python/ray/autoscaler/_private/fake_multi_node/example.yaml \
--head --block
```
5. Connect your application to the fake local cluster with `ray.init("auto")`.
6. Run `ray status` to view the status of your cluster, or `cat /tmp/ray/session_latest/logs/monitor.*` to view the autoscaler monitor log:
```shell
$ ray status
======== Autoscaler status: 2021-10-12 13:10:21.035674 ========
Node status
---------------------------------------------------------------
Healthy:
1 ray.head.default
2 ray.worker.cpu
Pending:
(no pending nodes)
Recent failures:
(no failures)
Resources
---------------------------------------------------------------
Usage:
0.0/10.0 CPU
0.00/70.437 GiB memory
0.00/10.306 GiB object_store_memory
Demands:
(no resource demands)
```
## Using `ray.cluster_utils.AutoscalingCluster`
To programmatically create a fake multi-node autoscaling cluster and connect to it, you can use [cluster_utils.AutoscalingCluster](https://github.com/ray-project/ray/blob/master/python/ray/cluster_utils.py). Here's an example of a basic autoscaling test that launches tasks triggering autoscaling:
```{literalinclude} /../../python/ray/tests/test_autoscaler_fake_multinode.py
:language: python
:dedent: 4
:start-after: __example_begin__
:end-before: __example_end__
```
Python documentation:
```{eval-rst}
.. autoclass:: ray.cluster_utils.AutoscalingCluster
:members:
```
## Features and limitations of `fake_multinode`
Most of the features of the autoscaler are supported in fake multi-node mode. For example, if you update the contents of the YAML file, the autoscaler picks up the new configuration and applies changes, as it does in a real cluster. Node selection, launch, and termination are governed by the same bin-packing and idle timeout algorithms as in a real cluster.
However, there are a few limitations:
1. All node raylets run uncontainerized on the local machine, so they share the same IP address. See the {ref}`fake_multinode_docker <fake-multinode-docker>` section for an alternative local multi-node setup.
2. Configurations for auth, setup, initialization, Ray start, file sync, and anything cloud-specific aren't supported.
3. You must limit the number of nodes, node CPU, and object store memory to avoid overloading your local machine.
(fake-multinode-docker)=
# Testing containerized multi-node clusters locally with Docker Compose
To go one step further and test a multi-node setup locally where each node uses its own container, with a separate filesystem, IP address, and Ray processes, you can use the `fake_multinode_docker` node provider.
The setup is similar to the {ref}`fake_multinode <fake-multinode>` provider. However, you need to start a monitoring process (`docker_monitor.py`) that runs the `docker compose` command.
Prerequisites:
1. Make sure you have [Docker](https://docs.docker.com/get-docker/) installed.
2. Make sure you have the [Docker Compose V2 plugin](https://docs.docker.com/compose/cli-command/#installing-compose-v2) installed.
## Using `RAY_FAKE_CLUSTER=1 ray up`
Complete the following steps:
1. Navigate to the root directory of the Ray repo you have cloned locally.
2. Locate the [fake_multi_node/example_docker.yaml](https://github.com/ray-project/ray/blob/master/python/ray/autoscaler/_private/fake_multi_node/example_docker.yaml) example file and fill in the number of CPUs and GPUs the local machine has for the head node type config. The YAML follows the same format as cluster autoscaler configurations, but some fields are not supported.
3. Configure worker types and other autoscaling configs as desired in the YAML file.
4. Make sure the `shared_volume_dir` is empty on the host system.
5. Start the monitoring process:
```shell
$ python ./python/ray/autoscaler/_private/fake_multi_node/docker_monitor.py \
./python/ray/autoscaler/_private/fake_multi_node/example_docker.yaml
```
6. Start the Ray cluster using `ray up`:
```shell
$ RAY_FAKE_CLUSTER=1 ray up -y ./python/ray/autoscaler/_private/fake_multi_node/example_docker.yaml
```
7. Connect your application to the fake local cluster with `ray.init("ray://localhost:10002")`.
8. Alternatively, get a shell on the head node:
```shell
$ docker exec -it fake_docker_fffffffffffffffffffffffffffffffffffffffffffffffffff00000_1 bash
```
## Using `ray.autoscaler._private.fake_multi_node.test_utils.DockerCluster`
You use this utility to write tests that use multi-node behavior. Use the `DockerCluster` class to set up a Docker Compose cluster in a temporary directory, start the monitoring process, wait for the cluster to come up, connect to it, and update the configuration.
See the API documentation and example test cases for how to use this utility.
```{eval-rst}
.. autoclass:: ray.autoscaler._private.fake_multi_node.test_utils.DockerCluster
:members:
```
## Features and limitations of `fake_multinode_docker`
The fake multinode docker node provider creates fully fledged nodes in their own containers. However, some limitations remain:
1. Configurations for auth, setup, initialization, Ray start, file sync, and anything cloud-specific aren't supported, but might be in the future.
2. You must limit the number of nodes, node CPU, and object store memory to avoid overloading your local machine.
3. In docker-in-docker setups, you must follow a careful setup to make the fake multinode docker provider work. See the following sections.
## Shared directories within the Docker environment
The containers mount two locations to host storage:
- `/cluster/node`: This location (in the container) points to `cluster_dir/nodes/<node_id>` (on the host). This location is individual per node, so the host can examine contents stored in this directory.
- `/cluster/shared`: This location (in the container) points to `cluster_dir/shared` (on the host). This location is shared across nodes and effectively acts as a shared filesystem (comparable to NFS).
## Setting up in a Docker-in-Docker (dind) environment
When setting up in a Docker-in-Docker (dind) environment, such as the Ray OSS Buildkite environment, keep some things in mind. To make this clear, consider these concepts:
* The **host** is the non-containerized machine that executes the code, for example a Buildkite runner.
* The **outer container** is the container running directly on the **host**. In the Ray OSS Buildkite environment, two containers are started: a *dind* network host and a container with the Ray source code and wheel.
* The **inner container** is a container started by the fake multinode docker node provider.
The control plane for the multinode docker node provider lives in the outer container. However, `docker compose` commands run from the connected docker-in-docker network. In the Ray OSS Buildkite environment, this is the `dind-daemon` container running on the host docker. For example, if you mounted `/var/run/docker.sock` from the host instead, it would be the host docker daemon. We refer to both as the **host daemon** from now on.
The outer container modifies files that must be mounted in the inner containers and modified from there as well. This means that the host daemon must also have access to these files.
Similarly, the inner containers expose ports, but because the host daemon starts the containers, the ports are only accessible on the host or the dind container.
For the Ray OSS Buildkite environment, we set the following environment variables:
* `RAY_TEMPDIR="/ray-mount"`. This environment variable defines where the temporary directory for the cluster files should be created. This directory must be accessible to the host, the outer container, and the inner container. In the inner container, we can control the directory name.
* `RAY_HOSTDIR="/ray"`. When the shared directory has a different name on the host, we can rewrite the mount points dynamically. In this example, the outer container is started with `-v /ray:/ray-mount` or similar, so the directory on the host is `/ray` and in the outer container `/ray-mount` (see `RAY_TEMPDIR`).
* `RAY_TESTHOST="dind-daemon"`. Because the host daemon starts the containers, we can't connect to `localhost`. The ports aren't exposed to the outer container. Thus, we can set the Ray host with this environment variable.
Lastly, Docker Compose requires a Docker image. The default Docker image is `rayproject/ray:nightly`. The Docker image requires `openssh-server` to be installed and enabled. In Buildkite, we build a new image from `rayproject/ray:nightly-py38-cpu` to avoid installing this on the fly for every node, which is the default. This base image is built in one of the previous build steps.
Thus, we set
* `RAY_DOCKER_IMAGE="rayproject/ray:multinode-py38"`
* `RAY_HAS_SSH=1`
to use this Docker image and inform our multinode infrastructure that SSH is already installed.
## Local development
If you're doing local development on the fake multi-node docker module, you can set
* `FAKE_CLUSTER_DEV="auto"`
This mounts the `ray/python/ray/autoscaler` directory to the started nodes. Note that this probably won't work in your docker-in-docker setup.
If you want to specify which top-level Ray directories to mount, you can use:
* `FAKE_CLUSTER_DEV_MODULES="autoscaler,tune"`
This mounts both `ray/python/ray/autoscaler` and `ray/python/ray/tune` within the node containers. The list of modules should be comma-separated and without spaces.
@@ -0,0 +1,382 @@
---
myst:
html_meta:
description: "The main guide to contributing to Ray, covering the pull request and code review workflow, coding style, the contributor license agreement, and how to find good first issues. Start here to learn how to submit and land a contribution to the Ray project."
---
```{include} /_includes/_latest_contribution_doc.rst
:parser: rst
```
(getting-involved)=
# Getting involved and contributing
```{toctree}
:hidden:
development
ci
docs
writing-style
writing-code-snippets
fake-autoscaler
testing-tips
debugging
profiling
agent-development
```
Ray is more than a framework for distributed applications. It's also an active community of developers, researchers, and folks who love machine learning.
:::{tip}
Ask questions on [our forum](https://discuss.ray.io/)! The community is extremely active in helping people succeed in building their Ray applications.
:::
You can join (and Star!) us [on GitHub](https://github.com/ray-project/ray).
## Contributing to Ray
We welcome and encourage all forms of contributions to Ray, including but not limited to:
- Code reviewing of patches and PRs.
- Pushing patches.
- Documentation and examples.
- Community participation in forums and issues.
- Code readability and code comments to improve readability.
- Test cases to make the codebase more robust.
- Tutorials, blog posts, talks that promote the project.
- Features and major changes via [Ray Enhancement Proposals (REP)](https://github.com/ray-project/enhancements).
## What can I work on?
We use GitHub labels to categorize issues and help contributors find work that matches their interests and skill level.
### Getting started
If you're new to Ray, start with these labels:
- [good-first-issue](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3A%22good-first-issue%22): Small issues that are good for new contributors to onboard to the codebase.
- [contribution-welcome](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3A%22contribution-welcome%22): Impactful issues that are good candidates for community contributions. We prioritize reviews for these issues.
### By component
Find issues in the area you're most interested in:
- [core](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Acore): Ray Core (tasks, actors, objects, scheduling).
- [data](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Adata): Ray Data for distributed data processing.
- [train](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Atrain): Ray Train for distributed training.
- [tune](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Atune): Ray Tune for hyperparameter tuning.
- [serve](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Aserve): Ray Serve for model serving.
- [rllib](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Arllib): RLlib for reinforcement learning.
### By type
Choose the kind of contribution you'd like to make:
- [bug](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Abug): Bug fixes.
- [enhancement](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement): New features or improvements.
- [docs](https://github.com/ray-project/ray/issues?q=is%3Aissue+is%3Aopen+label%3Adocs): Documentation improvements.
You can combine labels in GitHub's search to find issues that match multiple criteria.
## Setting up your development environment
To edit the Ray source code, fork the repository, clone it, and build Ray from source. Follow {ref}`these instructions for building <building-ray>` a local copy of Ray to make changes.
## Submitting and merging a contribution
To merge a contribution, complete the following steps:
1. First merge the most recent version of master into your development branch.
```bash
git remote add upstream https://github.com/ray-project/ray.git
git pull . upstream/master
```
2. Make sure all existing [tests](#testing) and [linters](#lint-and-formatting) pass. Run `setup_hooks.sh` to create a git hook that runs the linter before you push your changes.
3. If introducing a new feature or patching a bug, be sure to add new test cases in the relevant file in `ray/python/ray/tests/`.
4. Document the code. Document public functions, and remember to provide a usage example if applicable. See `doc/README.md` for instructions on editing and building public documentation.
5. Address comments on your PR. During the review process you may need to address merge conflicts with other changes. To resolve merge conflicts, run `git pull . upstream/master` on your branch. Don't use rebase, because it's less friendly to the GitHub review tool. We squash all commits on merge.
6. Reviewers approve and merge the pull request. Be sure to ping them if the pull request is getting stale.
## PR review process
### For contributors in the `ray-project` organization
- When you first create a PR, add a reviewer to the `assignee` section.
- Assignees review your PR and add the `@author-action-required` label if further action is required.
- Address their comments and remove the `@author-action-required` label from the PR.
- Repeat this process until assignees approve your PR.
- Once the PR is approved, the author is in charge of ensuring the PR passes the build. Add the `test-ok` label if the build succeeds.
- Committers merge the PR once the build passes.
### For contributors not in the `ray-project` organization
- Your PRs will have assignees shortly. Assignees of PRs actively engage with contributors to merge the PR.
- Actively ping assignees after you address your comments!
## Testing
Even though we have hooks to run unit tests automatically for each pull request, we recommend running unit tests locally beforehand to reduce reviewers' burden and speed up the review process.
If you're running tests for the first time, you can install the required dependencies with:
```shell
pip install -c python/requirements_compiled.txt -r python/requirements/test-requirements.txt
```
### Testing for Python development
The full suite of tests is too large to run on a single machine. However, you can run individual relevant Python test files. Suppose one of the tests in a file such as `python/ray/tests/test_basic.py` is failing. You can run just that test file locally as follows:
```shell
# Directly calling `pytest -v ...` may lose import paths.
python -m pytest -v -s python/ray/tests/test_basic.py
```
This runs all the tests in the file. To run a specific test, use the following:
```shell
# Directly calling `pytest -v ...` may lose import paths.
python -m pytest -v -s test_file.py::name_of_the_test
```
### Testing for C++ development
To compile and run all C++ tests, you can run:
```shell
bazel test $(bazel query 'kind(cc_test, ...)')
```
Alternatively, you can run one specific C++ test:
```shell
bazel test $(bazel query 'kind(cc_test, ...)') --test_filter=ClientConnectionTest --test_output=streamed
```
## Code style
In general, we follow the [Google style guide](https://google.github.io/styleguide/) for C++ code and the [Black code style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html) for Python code. Python imports follow [PEP8 style](https://peps.python.org/pep-0008/#imports). However, it's more important for code to be in a locally consistent style than to strictly follow guidelines. Whenever in doubt, follow the local code style of the component.
For Python documentation, we follow a subset of the [Google pydoc format](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html). The following code snippets demonstrate the canonical Ray pydoc formatting:
```{testcode}
def ray_canonical_doc_style(param1: int, param2: str) -> bool:
"""First sentence MUST be inline with the quotes and fit on one line.
Additional explanatory text can be added in paragraphs such as this one.
Do not introduce multi-line first sentences.
Examples:
.. doctest::
>>> # Provide code examples for key use cases, as possible.
>>> ray_canonical_doc_style(41, "hello")
True
>>> # A second example.
>>> ray_canonical_doc_style(72, "goodbye")
False
Args:
param1: The first parameter. Do not include the types in the
docstring. They should be defined only in the signature.
Multi-line parameter docs should be indented by four spaces.
param2: The second parameter.
Returns:
The return value. Do not include types here.
"""
```
```{testcode}
class RayClass:
"""The summary line for a class docstring should fit on one line.
Additional explanatory text can be added in paragraphs such as this one.
Do not introduce multi-line first sentences.
The __init__ method is documented here in the class level docstring.
All the public methods and attributes should have docstrings.
Examples:
.. testcode::
obj = RayClass(12, "world")
obj.increment_attr1()
Args:
param1: The first parameter. Do not include the types in the
docstring. They should be defined only in the signature.
Multi-line parameter docs should be indented by four spaces.
param2: The second parameter.
"""
def __init__(self, param1: int, param2: str):
#: Public attribute is documented here.
self.attr1 = param1
#: Public attribute is documented here.
self.attr2 = param2
@property
def attr3(self) -> str:
"""Public property of the class.
Properties created with the @property decorator
should be documented here.
"""
return "hello"
def increment_attr1(self) -> None:
"""Class methods are similar to regular functions.
See above about how to document functions.
"""
self.attr1 = self.attr1 + 1
```
See {ref}`How to write code snippets <writing-code-snippets_ref>` for more details about writing code snippets in docstrings.
### Lint and formatting
We also have tests for code formatting and linting that need to pass before merge.
* For Python formatting, install the [required dependencies](https://github.com/ray-project/ray/blob/master/python/requirements/lint-requirements.txt) first with:
```shell
pip install -c python/requirements_compiled.txt -r python/requirements/lint-requirements.txt
```
* If developing for C++, you need [clang-format](https://docs.kernel.org/dev-tools/clang-format.html) version `12`. Download this version of Clang from [the LLVM releases page](http://releases.llvm.org/download.html).
You can run the following locally:
```shell
pip install -U pre-commit==3.5.0
pre-commit install # automatic checks before committing
pre-commit run ruff -a
```
Output such as the following indicates failure:
```shell
WARNING: clang-format is not installed! # This is harmless
From https://github.com/ray-project/ray
* branch master -> FETCH_HEAD
python/ray/util/sgd/tf/tf_runner.py:4:1: F401 'numpy as np' imported but unused # Below is the failure
```
In addition, there are other formatting and semantic checkers, such as the following, that aren't included in `pre-commit`:
* Python README format:
```shell
cd python
python setup.py check --restructuredtext --strict --metadata
```
* Python and docs banned words check
```shell
./ci/lint/check-banned-words.sh
```
* Bazel format:
```shell
./ci/lint/bazel-format.sh
```
* clang-tidy for C++ lint, requires `clang` and `clang-tidy` version 12 to be installed:
```shell
./ci/lint/check-git-clang-tidy-output.sh
```
## Understanding CI test jobs
The Ray project automatically runs continuous integration (CI) tests once a PR is opened using [Buildkite](https://buildkite.com/ray-project/) with multiple CI test jobs.
The [CI](https://github.com/ray-project/ray/tree/master/ci) test folder contains all integration test scripts, which invoke other test scripts via `pytest`, `bazel`-based tests, or other bash scripts. Examples include:
* Bazel test command:
* `bazel test --build_tests_only //:all`
* Ray serving test commands:
* `pytest python/ray/serve/tests`
* `python python/ray/serve/examples/echo_full.py`
If a CI build exception doesn't appear to be related to your change, check [recent tests known to be flaky](https://flakey-tests.ray.io/).
## API compatibility style guide
Ray provides stability guarantees for its public APIs in Ray core and libraries, which are described in the {ref}`API Stability guide <api-stability>`.
It's hard to fully capture the semantics of API compatibility in a single annotation. For example, public APIs may have "experimental" arguments. Note more granular stability contracts in the pydoc, for example, "the `random_shuffle` option is experimental". When possible, prefix experimental arguments with underscores in Python, for example, `_owner=`.
**Other recommendations**:
In Python APIs, consider forcing the use of kwargs instead of positional arguments (with the `*` operator). Kwargs are easier to keep backward compatible than positional arguments. For example, if you needed to deprecate "opt1" below, it's easier with forced kwargs:
```python
def foo_bar(file, *, opt1=x, opt2=y)
pass
```
For callback APIs, consider adding a `**kwargs` placeholder as a "forward compatibility placeholder" in case you need to pass more args to the callback in the future, for example:
```python
def tune_user_callback(model, score, **future_kwargs):
pass
```
## Community examples
We're always looking for new example contributions! When contributing an example for a Ray library, include a link to your example in the `examples.yml` file for that library:
```yaml
- title: Serve a Java App
skill_level: advanced
link: tutorials/java
contributor: community
```
Give your example a title, a skill level (`beginner`, `intermediate`, or `advanced`), and a link. Relative links point to other documentation pages, but direct links starting with `http://` also work. Include the `contributor: community` metadata so the example is correctly labeled as a community example in the example gallery.
## Becoming a committer
Committers are experienced contributors who have demonstrated significant contributions to the Ray project over an extended period. Committers have additional responsibilities and privileges within the project.
**Eligibility criteria**
- Must be active in the project for at least six months
- Must be nominated by at least one TSC (Technical Steering Committee) member
- Must have demonstrated significant contributions to the project, including:
- High-quality code contributions
- Thorough code reviews
- Active participation in community discussions
- Technical expertise in one or more areas of the project
**Responsibilities**
Committers are expected to:
- Review and merge pull requests
- Ensure code quality and adherence to project standards
- Help maintain the health and direction of the project
- Mentor contributors and reviewers
## More resources for getting involved
```{include} involvement.md
```
:::{note}
These tips are based on the TVM [contributor guide](https://github.com/dmlc/tvm).
:::
+17
View File
@@ -0,0 +1,17 @@
---
myst:
html_meta:
description: "Entry point to Ray's developer and contributor guides, linking to API stability guarantees, API policy, the contribution workflow, configuration, and architecture whitepapers. Start here to navigate the documentation for developing and contributing to Ray itself."
---
# Developer guides
```{toctree}
:maxdepth: 2
stability
api-policy
getting-involved
../ray-core/configure
whitepaper
```
+8
View File
@@ -0,0 +1,8 @@
Ray is more than a framework for distributed applications. It's also an active community of developers, researchers, and folks who love machine learning. Here's a list of tips for getting involved with the Ray community:
- Join our [community Slack](https://www.ray.io/join-slack) to discuss Ray!
- Star and follow us [on GitHub](https://github.com/ray-project/ray).
- To post questions or feature requests, check out the [Discussion Board](https://discuss.ray.io/).
- Follow us and spread the word on [Twitter](https://x.com/raydistributed).
- Join our [Meetup Group](https://www.meetup.com/Bay-Area-Ray-Meetup/) to connect with others in the community.
- Use the `[ray]` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/ray) to ask and answer questions about Ray usage.
+147
View File
@@ -0,0 +1,147 @@
---
myst:
html_meta:
description: "Profiling guide for Ray contributors, including how to capture stack traces of C++ processes with gdb and analyze Ray's performance. Read this to diagnose high CPU usage, hangs, or bottlenecks in Ray internals."
---
(ray-core-internal-profiling)=
# Profiling for Ray developers
This guide helps contributors to the Ray project analyze Ray performance.
## Getting a stack trace of Ray C++ processes
You can use the following GDB command to view the current stack trace of any running Ray process (for example, raylet). This can be useful for debugging 100% CPU utilization or infinite loops. Run the command a few times to see what the process is stuck on.
```shell
sudo gdb -batch -ex "thread apply all bt" -p <pid>
```
Note that you can find the pid of the raylet with `pgrep raylet`.
## Installation
These instructions are for Ubuntu only. Attempts to get `pprof` to correctly symbolize on macOS have failed.
```bash
sudo apt-get install google-perftools libgoogle-perftools-dev
```
You may need to install `graphviz` for `pprof` to generate flame graphs.
```bash
sudo apt-get install graphviz
```
## CPU profiling
To launch Ray in profiling mode and profile Raylet, define the following variables:
```bash
export PERFTOOLS_PATH=/usr/lib/x86_64-linux-gnu/libprofiler.so
export PERFTOOLS_LOGFILE=/tmp/pprof.out
export RAY_RAYLET_PERFTOOLS_PROFILER=1
```
The file `/tmp/pprof.out` is empty until you let the binary run the target workload for a while and then `kill` it via `ray stop` or by letting the driver exit.
Note: Enabling `RAY_RAYLET_PERFTOOLS_PROFILER` allows profiling of the Raylet component. To profile other modules, use `RAY_{MODULE}_PERFTOOLS_PROFILER`, where `MODULE` represents the uppercase form of the process type, such as `GCS_SERVER`.
### Visualizing the CPU profile
You can visualize the output of `pprof` in different ways. Below, the output is a zoomable `.svg` image displaying the call graph annotated with hot paths.
```bash
# Use the appropriate path.
RAYLET=ray/python/ray/core/src/ray/raylet/raylet
google-pprof -svg $RAYLET /tmp/pprof.out > /tmp/pprof.svg
# Then open the .svg file with Chrome.
# If you realize the call graph is too large, use -focus=<some function> to zoom
# into subtrees.
google-pprof -focus=epoll_wait -svg $RAYLET /tmp/pprof.out > /tmp/pprof.svg
```
Below is a snapshot of an example SVG output, from the official documentation:
![Example pprof SVG call-graph output annotated with hot paths](http://goog-perftools.sourceforge.net/doc/pprof-test-big.gif)
## Memory profiling
To run memory profiling on Ray core components, use [jemalloc](https://github.com/jemalloc/jemalloc). Ray supports environment variables that override `LD_PRELOAD` on core components.
You can find the component name from `ray_constants.py`. For example, if you'd like to profile gcs_server, search `PROCESS_TYPE_GCS_SERVER` in `ray_constants.py`. You can see the value is `gcs_server`.
You must provide four environment variables for memory profiling.
* `RAY_JEMALLOC_LIB_PATH`: The path to the jemalloc shared library `libjemalloc.so`.
* `RAY_JEMALLOC_CONF`: The MALLOC_CONF configuration for jemalloc, using comma-separated values. Read [jemalloc docs](http://jemalloc.net/jemalloc.3.html) for more details.
* `RAY_JEMALLOC_PROFILE`: Comma-separated Ray components to run Jemalloc `.so`. For example, ("raylet,gcs_server"). Note that the components should match the process type in `ray_constants.py`. (It means "RAYLET,GCS_SERVER" won't work).
* `RAY_LD_PRELOAD_ON_WORKERS`: Default value is `0`, which means Ray doesn't preload Jemalloc for workers if a library is incompatible with Jemalloc. Set to `1` to instruct Ray to preload Jemalloc for a worker using values configured by `RAY_JEMALLOC_LIB_PATH` and `RAY_JEMALLOC_PROFILE`.
```bash
# Install jemalloc
wget https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2
tar -xf jemalloc-5.2.1.tar.bz2
cd jemalloc-5.2.1
export JEMALLOC_DIR=$PWD
./configure --enable-prof --enable-prof-libunwind
make
sudo make install
# Verify jeprof is installed.
which jeprof
# Start a Ray head node with jemalloc enabled.
# (1) `prof_prefix` defines the path to the output profile files and the prefix of their file names.
# (2) This example only profiles the GCS server component.
RAY_JEMALLOC_CONF=prof:true,lg_prof_interval:33,lg_prof_sample:17,prof_final:true,prof_leak:true,prof_prefix:$PATH_TO_OUTPUT_DIR/jeprof.out \
RAY_JEMALLOC_LIB_PATH=$JEMALLOC_DIR/lib/libjemalloc.so \
RAY_JEMALLOC_PROFILE=gcs_server \
ray start --head
# Check the output files. You should see files with the format of "jeprof.<pid>.0.f.heap".
# Example: jeprof.out.1904189.0.f.heap
ls $PATH_TO_OUTPUT_DIR/
# If you don't see any output files, try stopping the Ray cluster to force it to flush the
# profile data since `prof_final:true` is set.
ray stop
# Use jeprof to view the profile data. The first argument is the binary of GCS server.
# Note that you can also use `--pdf` or `--svg` to generate different formats of the profile data.
jeprof --text $YOUR_RAY_SRC_DIR/python/ray/core/src/ray/gcs/gcs_server $PATH_TO_OUTPUT_DIR/jeprof.out.1904189.0.f.heap
# [Example output]
Using local file ../ray/core/src/ray/gcs/gcs_server.
Using local file jeprof.out.1904189.0.f.heap.
addr2line: DWARF error: section .debug_info is larger than its filesize! (0x93f189 vs 0x530e70)
Total: 1.0 MB
0.3 25.9% 25.9% 0.3 25.9% absl::lts_20230802::container_internal::InitializeSlots
0.1 12.9% 38.7% 0.1 12.9% google::protobuf::DescriptorPool::Tables::CreateFlatAlloc
0.1 12.4% 51.1% 0.1 12.4% ::do_tcp_client_global_init
0.1 12.3% 63.4% 0.1 12.3% grpc_core::Server::Start
0.1 12.2% 75.6% 0.1 12.2% std::__cxx11::basic_string::_M_assign
0.1 12.2% 87.8% 0.1 12.2% std::__cxx11::basic_string::_M_mutate
0.1 12.2% 100.0% 0.1 12.2% std::__cxx11::basic_string::reserve
0.0 0.0% 100.0% 0.8 75.4% EventTracker::RecordExecution
...
```
## Running microbenchmarks
To run a set of single-node Ray microbenchmarks, use:
```bash
ray microbenchmark
```
You can find the microbenchmark results for Ray releases in the [GitHub release logs](https://github.com/ray-project/ray/tree/master/release/release_logs).
## References
- The [pprof documentation](http://goog-perftools.sourceforge.net/doc/cpu_profiler.html).
- A [Go version of pprof](https://github.com/google/pprof).
- The [gperftools](https://github.com/gperftools/gperftools), including libprofiler, tcmalloc, and other useful tools.
+61
View File
@@ -0,0 +1,61 @@
---
myst:
html_meta:
description: "Defines Ray's API stability guarantees and the PublicAPI (alpha, beta, stable), DeveloperAPI, and Deprecated annotations that label public interfaces. Read this to understand the stability to expect from a Ray API or how to annotate one you're adding."
---
(api-stability)=
# API stability
Ray provides stability guarantees for its public APIs in Ray core and libraries, which are decorated/labeled accordingly.
An API can be labeled:
* {ref}`PublicAPI <public-api-def>`, which means the API is exposed to end users. PublicAPI has three sub-levels (alpha, beta, stable), as described below.
* {ref}`DeveloperAPI <developer-api-def>`, which means the API is explicitly exposed to *advanced* Ray users and library developers.
* {ref}`Deprecated <deprecated-api-def>`, which may be removed in future releases of Ray.
Ray's PublicAPI stability definitions are based on the [Google stability level guidelines](https://google.aip.dev/181), with minor differences:
(api-stability-alpha)=
## Alpha
An *alpha* component undergoes rapid iteration with a known set of users who **must** be tolerant of change. The number of users **should** be a curated, manageable set, such that it is feasible to communicate with all of them individually.
Breaking changes **must** be both allowed and expected in alpha components, and users **must** have no expectation of stability.
(api-stability-beta)=
## Beta
A *beta* component **must** be considered complete and ready to be declared stable, subject to public testing.
Because users of beta components tend to have a lower tolerance of change, beta components **should** be as stable as possible; however, the beta component **must** be permitted to change over time. These changes **should** be minimal but **may** include backwards-incompatible changes to beta components.
Backwards-incompatible changes **must** be made only after a reasonable deprecation period to provide users with an opportunity to migrate their code.
(api-stability-stable)=
## Stable
A *stable* component **must** be fully-supported over the lifetime of the major API version. Because users expect such stability from components marked stable, there **must** be no breaking changes to these components within a major version (excluding extraordinary circumstances).
### Docstrings
```{eval-rst}
.. _public-api-def:
.. autofunction:: ray.util.annotations.PublicAPI
.. _developer-api-def:
.. autofunction:: ray.util.annotations.DeveloperAPI
.. _deprecated-api-def:
.. autofunction:: ray.util.annotations.Deprecated
```
Undecorated functions can be generally assumed to not be part of the Ray public API.
+132
View File
@@ -0,0 +1,132 @@
---
myst:
html_meta:
description: "Practical tips for testing Ray programs, such as fixing the resource quantity with ray.init(num_cpus=...) to avoid flaky, parallelism-dependent tests. Read this when writing reliable tests for code that uses Ray."
---
# Tips for testing Ray programs
Ray programs can be tricky to test due to the nature of parallel programs. We've put together a list of tips and tricks for common testing practices for Ray programs.
```{contents}
:local:
```
## Tip 1: Fixing the resource quantity with `ray.init(num_cpus=...)`
By default, `ray.init()` detects the number of CPUs and GPUs on your local machine/cluster.
However, your testing environment may have a significantly lower number of resources. For example, the TravisCI build environment only has [two cores](https://docs.travis-ci.com/user/reference/overview/).
If tests are written to depend on `ray.init()`, they may be implicitly written in a way that relies on a larger multi-core machine.
This may result in tests exhibiting unexpected, flaky, or faulty behavior that is hard to reproduce.
To overcome this, override the detected resources by setting them in `ray.init`, for example, `ray.init(num_cpus=2)`.
## Tip 2: Sharing the Ray cluster across tests if possible
It's safest to start a new Ray cluster for each test.
```{testcode}
import unittest
class RayTest(unittest.TestCase):
def setUp(self):
ray.init(num_cpus=4, num_gpus=0)
def tearDown(self):
ray.shutdown()
```
However, starting and stopping a Ray cluster can incur a non-trivial amount of latency. For example, on a typical MacBook Pro laptop, starting and stopping can take nearly five seconds:
```bash
python -c 'import ray; ray.init(); ray.shutdown()' 3.93s user 1.23s system 116% cpu 4.420 total
```
Across 20 tests, this ends up being 90 seconds of added overhead.
Reusing a Ray cluster across tests can provide significant speedups to your test suite. This reduces the overhead to a constant, amortized quantity:
```{testcode}
class RayClassTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Start it once for the entire test suite/module
ray.init(num_cpus=4, num_gpus=0)
@classmethod
def tearDownClass(cls):
ray.shutdown()
```
Depending on your application, there are certain cases where it may be unsafe to reuse a Ray cluster across tests. For example:
1. If your application depends on setting environment variables per process.
2. If your remote actor or task sets any sort of process-level global variables.
## Tip 3: Create a mini-cluster with `ray.cluster_utils.Cluster`
If writing an application for a cluster setting, you may want to mock a multi-node Ray cluster. You can do this with the `ray.cluster_utils.Cluster` utility.
:::{note}
On Windows, support for multi-node Ray clusters is experimental and untested. If you run into issues, file a report at <https://github.com/ray-project/ray/issues>.
:::
```{testcode}
from ray.cluster_utils import Cluster
# Starts a head-node for the cluster.
cluster = Cluster(
initialize_head=True,
head_node_args={
"num_cpus": 10,
})
```
After starting a cluster, you can execute a typical ray script in the same process:
```{testcode}
import ray
ray.init(address=cluster.address)
@ray.remote
def f(x):
return x
for _ in range(1):
ray.get([f.remote(1) for _ in range(1000)])
for _ in range(10):
ray.get([f.remote(1) for _ in range(100)])
for _ in range(100):
ray.get([f.remote(1) for _ in range(10)])
for _ in range(1000):
ray.get([f.remote(1) for _ in range(1)])
```
You can also add multiple nodes, each with different resource quantities:
```{testcode}
mock_node = cluster.add_node(num_cpus=10)
assert ray.cluster_resources()["CPU"] == 20
```
You can also remove nodes, which is useful when testing failure-handling logic:
```{testcode}
cluster.remove_node(mock_node)
assert ray.cluster_resources()["CPU"] == 10
```
See [`cluster_utils.py`](https://github.com/ray-project/ray/blob/master/python/ray/cluster_utils.py) for more details.
## Tip 4: Be careful when running tests in parallel
Since Ray starts a variety of services, it's easy to trigger timeouts if too many services start at once. Therefore, when using tools such as [pytest xdist](https://pypi.org/project/pytest-xdist/) that run multiple tests in parallel, keep in mind that this may introduce flakiness into the test environment.
+13
View File
@@ -0,0 +1,13 @@
---
myst:
html_meta:
description: "Links to the Ray 2.0 and 1.0 architecture whitepapers and the Exoshuffle paper for in-depth coverage of Ray's internals, dataplane, scalability, and performance. Visit for authoritative deep-dives into Ray's architecture and design."
---
(whitepaper)=
# Architecture whitepapers
For an in-depth overview of Ray internals, check out the [Ray 2.0 Architecture whitepaper](https://docs.google.com/document/d/1tBw9A4j62ruI5omIJbMxly-la5w4q_TjyJgJL_jN2fI/preview). For the previous version, see the [v1.0 whitepaper](https://docs.google.com/document/d/1lAy0Owi-vPz2jEqBSaHNQcy2IBSDEHyXNOQZlGuj93c/preview).
For more about the scalability and performance of the Ray dataplane, see the [Exoshuffle paper](https://arxiv.org/abs/2203.05072).
@@ -0,0 +1,349 @@
---
myst:
html_meta:
description: "Guide to writing runnable, CI-tested code examples for Ray docs using doctest-style, code-output-style, and literalinclude formats. Read this when adding code snippets to docstrings or user guides so they keep working for users."
---
(writing-code-snippets_ref)=
# How to write code snippets
Users learn from example. So, whether you're writing a docstring or a user guide, include examples that illustrate the relevant APIs. Your examples should run out-of-the-box so that users can copy them and adapt them to their own needs.
This page describes how to write code snippets so that they're tested in CI.
:::{note}
The examples in this guide use reStructuredText. If you're writing Markdown, use MyST syntax. To learn more, read the [MyST documentation](https://myst-parser.readthedocs.io/en/latest/syntax/roles-and-directives.html#directives-a-block-level-extension-point).
:::
## Types of examples
There are three types of examples: *doctest-style*, *code-output-style*, and *literalinclude*.
### *doctest-style* examples
*doctest-style* examples mimic interactive Python sessions.
```
.. doctest::
>>> def is_even(x):
... return (x % 2) == 0
>>> is_even(0)
True
>>> is_even(1)
False
```
They're rendered like this:
```{doctest}
>>> def is_even(x):
... return (x % 2) == 0
>>> is_even(0)
True
>>> is_even(1)
False
```
:::{tip}
If you're writing docstrings, exclude `.. doctest::` to simplify your code:
```
Example:
>>> def is_even(x):
... return (x % 2) == 0
>>> is_even(0)
True
>>> is_even(1)
False
```
:::
### *code-output-style* examples
*code-output-style* examples contain ordinary Python code.
```
.. testcode::
def is_even(x):
return (x % 2) == 0
print(is_even(0))
print(is_even(1))
.. testoutput::
True
False
```
They're rendered like this:
```{testcode}
def is_even(x):
return (x % 2) == 0
print(is_even(0))
print(is_even(1))
```
```{testoutput}
True
False
```
### *literalinclude* examples
*literalinclude* examples display Python modules.
```
.. literalinclude:: ./doc_code/example_module.py
:language: python
:start-after: __is_even_begin__
:end-before: __is_even_end__
```
```{literalinclude} ./doc_code/example_module.py
:language: python
```
They're rendered like this:
```{literalinclude} ./doc_code/example_module.py
:language: python
:start-after: __is_even_begin__
:end-before: __is_even_end__
```
## Which type of example should you write?
There's no hard rule about which style you should use. Choose the style that best illustrates your API.
:::{tip}
If you're not sure which style to use, use *code-output-style*.
:::
### When to use *doctest-style*
If you're writing a small example that emphasizes object representations, or if you want to print intermediate objects, use *doctest-style*.
```
.. doctest::
>>> import ray
>>> ds = ray.data.range(100)
>>> ds.schema()
Column Type
------ ----
id int64
>>> ds.take(5)
[{'id': 0}, {'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]
```
### When to use *code-output-style*
If you're writing a longer example, or if object representations aren't relevant to your example, use *code-output-style*.
```
.. testcode::
from typing import Dict
import numpy as np
import ray
ds = ray.data.read_csv("s3://anonymous@air-example-data/iris.csv")
# Compute a "petal area" attribute.
def transform_batch(batch: Dict[str, np.ndarray]) -> Dict[str, np.ndarray]:
vec_a = batch["petal length (cm)"]
vec_b = batch["petal width (cm)"]
batch["petal area (cm^2)"] = np.round(vec_a * vec_b, 2)
return batch
transformed_ds = ds.map_batches(transform_batch)
print(transformed_ds.materialize())
.. testoutput::
shape: (150, 6)
╭───────────────────┬──────────────────┬───────────────────┬──────────────────┬────────┬───────────────────╮
│ sepal length (cm) ┆ sepal width (cm) ┆ petal length (cm) ┆ petal width (cm) ┆ target ┆ petal area (cm^2) │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ double ┆ double ┆ double ┆ double ┆ int64 ┆ double │
╞═══════════════════╪══════════════════╪═══════════════════╪══════════════════╪════════╪═══════════════════╡
│ 5.1 ┆ 3.5 ┆ 1.4 ┆ 0.2 ┆ 0 ┆ 0.28 │
│ 4.9 ┆ 3.0 ┆ 1.4 ┆ 0.2 ┆ 0 ┆ 0.28 │
│ 4.7 ┆ 3.2 ┆ 1.3 ┆ 0.2 ┆ 0 ┆ 0.26 │
│ 4.6 ┆ 3.1 ┆ 1.5 ┆ 0.2 ┆ 0 ┆ 0.3 │
│ 5.0 ┆ 3.6 ┆ 1.4 ┆ 0.2 ┆ 0 ┆ 0.28 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 6.7 ┆ 3.0 ┆ 5.2 ┆ 2.3 ┆ 2 ┆ 11.96 │
│ 6.3 ┆ 2.5 ┆ 5.0 ┆ 1.9 ┆ 2 ┆ 9.5 │
│ 6.5 ┆ 3.0 ┆ 5.2 ┆ 2.0 ┆ 2 ┆ 10.4 │
│ 6.2 ┆ 3.4 ┆ 5.4 ┆ 2.3 ┆ 2 ┆ 12.42 │
│ 5.9 ┆ 3.0 ┆ 5.1 ┆ 1.8 ┆ 2 ┆ 9.18 │
╰───────────────────┴──────────────────┴───────────────────┴──────────────────┴────────┴───────────────────╯
(Showing 10 of 150 rows)
```
### When to use *literalinclude*
If you're writing an end-to-end example and your example doesn't contain outputs, use *literalinclude*.
## How to handle hard-to-test examples
### When is it okay to not test an example?
You don't need to test examples that depend on external systems such as Weights and Biases.
### Skipping *doctest-style* examples
To skip a *doctest-style* example, append `# doctest: +SKIP` to your Python code.
```
.. doctest::
>>> import ray
>>> ray.data.read_images("s3://private-bucket") # doctest: +SKIP
```
### Skipping *code-output-style* examples
To skip a *code-output-style* example, add `:skipif: True` to the `testcode` block.
```
.. testcode::
:skipif: True
from ray.air.integrations.wandb import WandbLoggerCallback
callback = WandbLoggerCallback(
project="Optimization_Project",
api_key_file=...,
log_config=True
)
```
## How to handle long or non-deterministic outputs
If your Python code is non-deterministic, or if your output is excessively long, you can skip all or part of the output.
### Ignoring *doctest-style* outputs
To ignore parts of a *doctest-style* output, replace problematic sections with ellipses.
```
>>> import ray
>>> ray.data.read_images("s3://anonymous@ray-example-data/image-datasets/simple")
Dataset(num_rows=..., schema=...)
```
To ignore an output altogether, write a *code-output-style* snippet. Don't use `# doctest: +SKIP`.
### Ignoring *code-output-style* outputs
If parts of your output are long or non-deterministic, replace problematic sections with ellipses.
```
.. testcode::
import ray
ds = ray.data.read_images("s3://anonymous@ray-example-data/image-datasets/simple")
print(ds)
.. testoutput::
Dataset(num_rows=..., schema=...)
```
If your output is non-deterministic and you want to display a sample output, add `:options: +MOCK`.
```
.. testcode::
import random
print(random.random())
.. testoutput::
:options: +MOCK
0.969461416250246
```
If your output is hard to test and you don't want to display a sample output, exclude the `testoutput`.
```
.. testcode::
print("This output is hidden and untested")
```
## How to test examples with GPUs
To configure Bazel to run an example with GPUs, complete the following steps:
1. Open the corresponding `BUILD` file. If your example is in the `doc/` folder, open `doc/BUILD`. If your example is in the `python/` folder, open a file such as `python/ray/train/BUILD`.
2. Locate the `doctest` rule. It looks like this:
```
doctest(
files = glob(
include=["source/**/*.rst"],
),
size = "large",
tags = ["team:none"]
)
```
3. Add the file that contains your example to the list of excluded files.
```
doctest(
files = glob(
include=["source/**/*.rst"],
exclude=["source/data/requires-gpus.rst"]
),
tags = ["team:none"]
)
```
4. If it doesn't already exist, create a `doctest` rule with `gpu` set to `True`.
```
doctest(
files = [],
tags = ["team:none"],
gpu = True
)
```
5. Add the file that contains your example to the GPU rule.
```
doctest(
files = ["source/data/requires-gpus.rst"]
size = "large",
tags = ["team:none"],
gpu = True
)
```
For a practical example, see `doc/BUILD` or `python/ray/train/BUILD`.
## How to locally test examples
To locally test examples, install the Ray fork of `pytest-sphinx`.
```bash
pip install git+https://github.com/ray-project/pytest-sphinx
```
Then, run pytest on a module, docstring, or user guide.
```bash
pytest --doctest-modules python/ray/data/read_api.py
pytest --doctest-modules python/ray/data/read_api.py::ray.data.read_api.range
pytest --doctest-modules doc/source/data/getting-started.rst
```
+343
View File
@@ -0,0 +1,343 @@
---
myst:
html_meta:
description: "The Ray documentation style and grammar guide: voice, word choice, sentence structure, headings, lists, links, admonitions, and MyST formatting conventions. Read this before writing or editing Ray documentation, whether you're a human contributor or an AI coding agent."
---
(documentation-style)=
# Ray documentation style guide
This page is the style and grammar standard for the Ray documentation. It covers how to write Ray docs: voice, word choice, sentence structure, headings, lists, links, admonitions, and MyST formatting. Read it before you write or edit a page, then apply it as you go.
The guidance here is for everyone who writes Ray docs, including AI coding agents. When an agent edits documentation under `doc/source/`, it follows this guide. See {ref}`agent-development` for how the repository configures AI coding agents.
## How to use this guide
When two rules conflict, follow this order:
1. This guide.
1. The [Google developer documentation style guide](https://developers.google.com/style), as the general fallback for anything this guide doesn't cover.
Vale enforces an automated subset of the Google style guide in CI, currently on the Ray Data docs and the example gallery. Passing Vale is the baseline, not the whole standard. This guide is broader than what Vale checks, so a page can pass Vale and still need edits to meet the standard here. For how to run Vale, see {ref}`vale`.
New pages are MyST Markdown (`.md`). A lint check rejects newly added reStructuredText (`.rst`) files, though edits to existing `.rst` files are fine. The examples in this guide use MyST. The prose rules apply to both formats. Only the formatting and cross-reference syntax differs.
## Voice and grammar
### Write in active voice
Name the actor and put it in front of the verb. Passive voice hides who does what.
- Use: "The scheduler retries failed tasks."
- Not: "Failed tasks are retried by the scheduler."
Keep passive voice when the object is the real focus, when the actor is unknown, or when naming the actor adds nothing. "The object is spilled to disk" is fine when the point is what happens to the object, not what spills it.
### Write in present tense
Describe current behavior in the present tense. Avoid "will" for things that are always true.
- Use: "Ray Serve routes the request to a replica."
- Not: "Ray Serve will route the request to a replica."
### Address the reader as "you"
Write in second person. Don't write about "the user" or "developers" in the abstract.
- Use: "You can configure the number of replicas."
- Not: "Users can configure the number of replicas."
### Use the imperative for instructions
Write steps and commands as direct instructions.
- Use: "Set `num_cpus` to reserve cores for the task."
- Not: "You should set `num_cpus` to reserve cores for the task."
### Avoid first-person plural
Don't write "we," "our," or "let's." Rewrite the sentence to remove the first person. Address the reader with "you" or the imperative, or make the feature the subject. When a sentence genuinely needs a subject that acts on behalf of the project, use "The Ray project" or the relevant component.
- Use: "Ray tests every code snippet in the documentation." Not: "We test every code snippet."
- Use: "To build the docs, follow these steps:" Not: "Let's build the docs."
- Use: "The Ray project welcomes contributions of all kinds." Not: "We welcome all contributions."
### Capitalize Ray components and product names
Capitalize Ray and its libraries: Ray, Ray Core, Ray Data, Ray Serve, Ray Train, Ray Tune, RLlib. Capitalize other proper nouns: Python, Sphinx, AWS, GCP, Kubernetes. Lowercase generic nouns even when they name a Ray concept: task, actor, object, cluster, worker, node, placement group.
### Define acronyms on first use
Spell out the full term the first time, with the acronym in parentheses: "reinforcement learning (RL)." Use the acronym consistently afterward. Don't redefine it later on the same page.
### Keep comparisons precise
State what's better and by what measure. Vague comparisons read as marketing.
- Use: "Streaming execution uses less memory than materializing the full dataset."
- Not: "Streaming execution is better."
### Keep parallel structure
Match the grammatical form of items in a series and avoid redundant conjunctions.
- Use: "This preserves throughput while reducing memory usage."
- Not: "This preserves throughput and can also reduce memory usage."
## Word choice
### Use contractions
Contractions read naturally: don't, doesn't, can't, won't, it's, you're, isn't, aren't, wouldn't, shouldn't. Avoid contractions in a warning or an error message, where the extra weight of the full form helps.
Never use "would've," "could've," "should've," "ain't," or "y'all."
### Use "such as," not "like," for examples
Reserve "like" for genuine comparisons.
- Use: "distributed frameworks such as Ray"
- Not: "distributed frameworks like Ray"
- Fine: "The API behaves like a Python dictionary." (a real comparison)
### Cut qualifiers and filler
Delete words that add no information: simply, just, basically, actually, really, very, quite, easily, of course, obviously, clearly, note that. Also drop the sentiment adverbs "luckily," "fortunately," and "unfortunately."
- Use: "Call `ray.get` to retrieve the result."
- Not: "You can simply just call `ray.get` to retrieve the result."
### Prefer plain words
Choose the simpler word.
- "utilize" or "leverage" → "use"
- "in order to" → "to"
- "prior to" → "before"
- "due to the fact that" → "because"
- "via" → "through" or "with"
### Turn hedging into direct advice
Recommend directly. Don't soften real guidance into a suggestion.
- "Prefer X" → "Use X"
- "Consider using X" → "Use X"
- "You might want to enable caching" → "Enable caching."
Keep "might," "can," or "may" when they express genuine possibility, as in "The build might fail if the network is unstable."
### Focus on what the reader does
Avoid "lets," "allows," and "enables." They describe what the product permits instead of what the reader accomplishes.
- Use: "Scale a deployment by adding replicas."
- Not: "Ray Serve lets you scale a deployment."
### Streamline references
- "Please refer to" → "See"
- "Refer to the configuration guide" → "See the configuration guide"
- "Check the API documentation" → "See the API documentation"
### Write "ID," not "id"
In prose, write "ID" (or "IDs"). Reserve `id` for code, where it's a literal identifier.
- Use: "Ray assigns each task a task ID."
- Not: "Ray assigns each task a task id."
### Use words for symbols in prose
Outside code, spell out operators and separators.
- "X + Y" → "X and Y"
- "X vs. Y" → "X versus Y"
- "X/Y" → "X or Y" or "X and Y"
### Don't write "etc." after "such as," "for example," or "including"
Those phrases already signal a partial list. Give specific examples, or end with "and more" if you must.
### Avoid time-relative words
Words such as "currently," "recently," "new," "now," and "at this time" go stale as Ray evolves. Remove them, or replace them with a specific version when the timing matters.
- Use: "Ray Serve supports synchronous handlers." Or: "As of Ray 2.9, Ray Serve supports asynchronous handlers."
- Not: "Ray Serve currently supports synchronous handlers."
### Use angle brackets for placeholders
Mark values the reader replaces with angle brackets, not uppercase.
- Use: `ray start --address=<head-node-ip>:6379`
- Not: `ray start --address=HEAD_NODE_IP:6379`
Uppercase placeholders are ambiguous with real constants and environment variables.
## Sentence structure
Prefer short, direct sentences. Split a long sentence into two rather than joining clauses with punctuation.
Avoid dashes (`--`, em dashes, en dashes), parentheticals, and semicolons in prose. Restructure instead. Use a colon only to introduce a list or a code block.
- Use: "Ray splits the nodes into two groups: spot and on-demand. Ray ranks on-demand above spot."
- Not: "Ray splits the nodes into two groups -- spot and on-demand -- and ranks them (on-demand first)."
## Headings
Use sentence case for every heading. Capitalize only the first word and proper nouns.
- Use: "Configure the runtime environment"
- Not: "Configure the Runtime Environment"
Write conceptual headings as questions and task headings as imperatives. Keep them short.
- Conceptual: "What is a placement group?"
- Task: "Launch a cluster on AWS"
- Too long: "Understanding the fundamentals of placement groups" → "Placement group basics"
Don't stack heading levels without prose between them. A section heading that introduces subsections needs a lead-in paragraph first. Avoid nesting beyond the fourth level; reaching that depth usually means the page should be split.
## Lists and punctuation
Use a list to enumerate things, map topics to pages, or present a scannable reference. Don't use a list to explain how something works or to sell benefits. Fold that into prose.
End a list item with a period when it's a complete sentence or contains a verb. Leave brief noun phrases unpunctuated. Be consistent within a single list.
Write list lead-ins as complete sentences, and end them with a colon.
- Use: "To invite users, do the following:"
- Not: "To invite users:"
Use the Oxford comma: "tasks, actors, and objects."
When you name a fixed set, state the count: "Ray offers two scheduling strategies:" rather than "Ray offers several scheduling strategies:".
In Markdown, number every ordered-list item `1.`. MyST renders them in source order, so writing `1.` throughout means inserting or reordering a step is a one-line edit instead of a renumber pass.
## Formatting
### Admonitions
Use MyST admonitions for asides, not bold inline labels. Ray uses `note`, `tip`, `warning`, `caution`, and `important`:
````markdown
:::{note}
Ray caches the object in the local object store.
:::
````
Choose the level by severity. Use `tip` for optional advice, `note` for supporting information, `caution` for something that needs care, and `warning` for an action that can lose data or break a workload. Convert a standalone caveat or limitation into the matching admonition so it stands out instead of hiding in a paragraph.
### Code blocks
Tag every fenced code block with a language: `python`, `bash`, `yaml`, `json`, `text`, or `dockerfile`. Don't prefix shell commands with `$` or `#`, so readers can copy and paste them.
Every runnable snippet in the docs is tested. Write examples that run out of the box, and use `literalinclude` or a testable code cell rather than pasting untested code. See {ref}`How to write code snippets <writing-code-snippets_ref>`.
In code comments, start with a capital letter and use the imperative.
- Use: `# Reserve two GPUs for the actor.`
- Not: `# this reserves two gpus`
### Bold and italics
Italicize a term when you first define it. Reserve bold for three uses: the name of a UI element (a button, menu, tab, or field), the short lead-in label of an admonition, and the term in a bold definition list (`**Term**: explanation`).
Don't bold ordinary prose for emphasis, and don't bold inline code. Code styling already sets it apart. Pervasive bold reads as shouting.
- Use: "supports capacity reservations, spot instances, and on-demand instances"
- Not: "supports **capacity reservations**, **spot instances**, and **on-demand instances**"
### Tables
Use a Markdown table for simple rows with single-line cells. Always include a header row, and introduce the table with a sentence of prose. For cells that hold code blocks, multiple lines, or other complex content, use the `list-table` directive:
````markdown
:::{list-table} Scheduling strategies
:header-rows: 1
* - Strategy
- Behavior
* - `DEFAULT`
- Packs tasks onto the fewest nodes.
* - `SPREAD`
- Spreads tasks across available nodes.
:::
````
## Links and cross-references
Ray docs use Sphinx cross-references, which resolve at build time and survive page moves. Prefer them over hardcoded URLs to other docs pages.
- Link to a whole page with the `{doc}` role: `` {doc}`writing-code-snippets` ``. Use `{doc}` when the target's source is `.rst`. A bare `[text](path.md)` link to an `.rst` source emits `myst.xref_missing`, which fails the build.
- Link to a labeled target with the `{ref}` role: `` {ref}`vale` `` or `` {ref}`custom text <vale>` ``. Define the target with a MyST label on the line above the heading:
```markdown
(my-label)=
## The section to link
```
- Link between `.md` pages with a standard Markdown link: `[text](other-page.md)`.
- Link to the API reference with autodoc cross-reference roles, such as `` {py:func}`ray.init` `` or `` {py:class}`ray.data.Dataset` ``.
Write descriptive link text that says where the link goes. Don't write `click [here](path).` Wrap external URLs in Markdown; don't paste a bare URL into prose.
Link to a given page once per section. Repeating a link in a later section is fine when readers might enter the page at different points. For a cluster of related links, gather them under a "See also" list at the end of the section.
## MyST and Markdown specifics
### Soft-wrap prose
Write one logical line per paragraph and list item, and let your editor wrap the display. Don't hard-wrap prose at a fixed column. One paragraph is one source line, however long. Hard wrapping makes diffs noisy and edits awkward.
### Front matter
Give every page a `description` in its MyST `html_meta` front matter. Search engines and the page's social preview use it:
```markdown
---
myst:
html_meta:
description: "One or two sentences describing what the page covers."
---
```
### Numbers and units
Spell out zero through nine in prose. Use numerals for 10 and above. Don't wrap a single-digit number in backticks when it carries a unit: write "1 GiB," not "`1` GiB." Use backticks for configuration values, as in `num_replicas: 1`.
### Alt text
Give every image descriptive alt text that says what the image shows. Don't write "screenshot of..." or "image of...".
### HTML comments
Preserve existing HTML comments that read as author notes. They're working notes contributors leave for each other across revisions. Don't remove or reword them as part of an unrelated edit.
## Write for humans
Documentation should read as though a person wrote it, because a person should have.
- Vary your sentence and list structure. Don't produce perfectly symmetrical bullet lists where every item has the same shape and length.
- Explain how something works in prose, not a numbered list. Reserve numbered lists for sequential steps.
- Cut benefits lists. If a feature is worth recommending, recommend it directly. Don't follow "This approach provides:" with a list of adjectives.
- Skip opening previews. Don't open a section with a bullet list that restates the headings below it. Start with substance.
- Open a page with one or two sentences that say what it covers, then get into the content.
## Don't fabricate technical details
Every technical claim needs a verifiable source: existing Ray documentation, the source code, a configuration file, or something the contributor gives you. Don't invent behavior from what seems plausible, extrapolate implementation details from a feature name, or guess at metrics, defaults, or version cutoffs.
When you can't verify a detail, leave it out. Incomplete but accurate documentation beats complete but partly fabricated documentation. This matters most for AI agents, which can produce fluent, confident prose that's wrong. Fabrication is the most damaging error in documentation.
## Choosing a format
Pick the format that makes the information easiest to extract:
- Enumerating distinct things, such as options or components, is a list.
- Explaining what something is or how it works is prose.
- Mapping topics to pages, or comparing options side by side, is a table.
- Listing benefits is usually a cut. Fold the one point that matters into prose.