mirror of
https://github.com/astral-sh/uv
synced 2026-01-22 05:50:25 -05:00
<!-- Thank you for contributing to uv! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary Current documentation requires contributors to have Node.js/npm installed locally to format Markdown files. This might be problematic for users who don't work with JavaScript ecosystem or users who want to avoid toolchain setup. This change adds docker-based alternative: ``` docker run --rm -v .:/src/ -w /src/ node:alpine npx prettier --prose-wrap always --write "**/*.md" ``` Which mounts current working directory into /src/ inside of a container and also sets working directory (-w) to /src/ so prettier loads .editorconfig. <!-- What's the purpose of the change? What does it do, and why? --> ## Test Plan Both commands should produce the same output <details> <summary>Native Prettier</summary> ```console ➜ uv git:(docs/contributing-md-formatting) npx prettier --prose-wrap always --write "**/*.md" .github/PULL_REQUEST_TEMPLATE.md 28ms (unchanged) BENCHMARKS.md 30ms (unchanged) changelogs/0.1.x.md 264ms (unchanged) changelogs/0.2.x.md 223ms (unchanged) changelogs/0.3.x.md 29ms (unchanged) changelogs/0.4.x.md 126ms (unchanged) changelogs/0.5.x.md 153ms (unchanged) changelogs/0.6.x.md 77ms (unchanged) CONTRIBUTING.md 9ms (unchanged) crates/README.md 4ms (unchanged) crates/uv-build/README.md 1ms (unchanged) crates/uv-client/README.md 1ms (unchanged) crates/uv-globfilter/README.md 3ms (unchanged) crates/uv-pep440/Readme.md 6ms (unchanged) crates/uv-pep508/Readme.md 3ms (unchanged) crates/uv-python/python/packaging/README.md 1ms (unchanged) crates/uv-trampoline/README.md 14ms (unchanged) crates/uv-virtualenv/README.md 1ms (unchanged) docs/concepts/authentication.md 10ms (unchanged) docs/concepts/build-backend.md 11ms (unchanged) docs/concepts/cache.md 17ms (unchanged) docs/concepts/configuration-files.md 9ms (unchanged) docs/concepts/index.md 2ms (unchanged) docs/concepts/indexes.md 22ms (unchanged) docs/concepts/projects/build.md 4ms (unchanged) docs/concepts/projects/config.md 25ms (unchanged) docs/concepts/projects/dependencies.md 29ms (unchanged) docs/concepts/projects/index.md 2ms (unchanged) docs/concepts/projects/init.md 10ms (unchanged) docs/concepts/projects/layout.md 10ms (unchanged) docs/concepts/projects/run.md 4ms (unchanged) docs/concepts/projects/sync.md 11ms (unchanged) docs/concepts/projects/workspaces.md 12ms (unchanged) docs/concepts/python-versions.md 26ms (unchanged) docs/concepts/resolution.md 40ms (unchanged) docs/concepts/tools.md 19ms (unchanged) docs/getting-started/features.md 8ms (unchanged) docs/getting-started/first-steps.md 2ms (unchanged) docs/getting-started/help.md 8ms (unchanged) docs/getting-started/index.md 2ms (unchanged) docs/getting-started/installation.md 8ms (unchanged) docs/guides/index.md 2ms (unchanged) docs/guides/install-python.md 31ms (unchanged) docs/guides/integration/alternative-indexes.md 21ms (unchanged) docs/guides/integration/aws-lambda.md 49ms (unchanged) docs/guides/integration/dependency-bots.md 16ms (unchanged) docs/guides/integration/docker.md 37ms (unchanged) docs/guides/integration/fastapi.md 8ms (unchanged) docs/guides/integration/github.md 36ms (unchanged) docs/guides/integration/index.md 4ms (unchanged) docs/guides/integration/jupyter.md 17ms (unchanged) docs/guides/integration/marimo.md 11ms (unchanged) docs/guides/integration/pre-commit.md 27ms (unchanged) docs/guides/integration/pytorch.md 12ms (unchanged) docs/guides/package.md 5ms (unchanged) docs/guides/projects.md 12ms (unchanged) docs/guides/scripts.md 19ms (unchanged) docs/guides/tools.md 8ms (unchanged) docs/index.md 7ms (unchanged) docs/pip/compatibility.md 44ms (unchanged) docs/pip/compile.md 13ms (unchanged) docs/pip/dependencies.md 3ms (unchanged) docs/pip/environments.md 10ms (unchanged) docs/pip/index.md 2ms (unchanged) docs/pip/inspection.md 1ms (unchanged) docs/pip/packages.md 3ms (unchanged) docs/reference/benchmarks.md 3ms (unchanged) docs/reference/index.md 3ms (unchanged) docs/reference/installer.md 2ms (unchanged) docs/reference/policies/index.md 2ms (unchanged) docs/reference/policies/license.md 2ms (unchanged) docs/reference/policies/platforms.md 4ms (unchanged) docs/reference/policies/versioning.md 2ms (unchanged) docs/reference/resolver-internals.md 19ms (unchanged) docs/reference/troubleshooting/build-failures.md 13ms (unchanged) docs/reference/troubleshooting/index.md 1ms (unchanged) docs/reference/troubleshooting/reproducible-examples.md 7ms (unchanged) PIP_COMPATIBILITY.md 1ms (unchanged) README.md 10ms (unchanged) scripts/benchmark/README.md 1ms (unchanged) scripts/packages/built-by-uv/README.md 1ms (unchanged) scripts/packages/dependent_locals/first_local/README.md 0ms (unchanged) scripts/packages/dependent_locals/second_local/README.md 0ms (unchanged) scripts/packages/hatchling_editable/README.md 0ms (unchanged) scripts/packages/README.md 1ms (unchanged) scripts/packages/root_editable/README.md 0ms (unchanged) scripts/workspaces/albatross-virtual-workspace/packages/Unrelated.md 1ms (unchanged) SECURITY.md 2ms (unchanged) STYLE.md 9ms (unchanged) ➜ uv git:(docs/contributing-md-formatting) git status On branch docs/contributing-md-formatting nothing to commit, working tree clean ➜ uv git:(docs/contributing-md-formatting) ``` </details> <details> <summary>Docker based</summary> ```console ➜ uv git:(docs/contributing-md-formatting) sudo docker run --rm -v .:/src/ -w /src/ node:alpine npx prettier --prose-wrap always --write "**/*.md" npm warn exec The following package was not found and will be installed: prettier@3.6.0 .github/PULL_REQUEST_TEMPLATE.md 54ms (unchanged) BENCHMARKS.md 41ms (unchanged) changelogs/0.1.x.md 297ms (unchanged) changelogs/0.2.x.md 306ms (unchanged) changelogs/0.3.x.md 50ms (unchanged) changelogs/0.4.x.md 137ms (unchanged) changelogs/0.5.x.md 217ms (unchanged) changelogs/0.6.x.md 114ms (unchanged) CONTRIBUTING.md 12ms (unchanged) crates/README.md 8ms (unchanged) crates/uv-build/README.md 2ms (unchanged) crates/uv-client/README.md 2ms (unchanged) crates/uv-globfilter/README.md 6ms (unchanged) crates/uv-pep440/Readme.md 8ms (unchanged) crates/uv-pep508/Readme.md 5ms (unchanged) crates/uv-python/python/packaging/README.md 2ms (unchanged) crates/uv-trampoline/README.md 17ms (unchanged) crates/uv-virtualenv/README.md 2ms (unchanged) docs/concepts/authentication.md 20ms (unchanged) docs/concepts/build-backend.md 20ms (unchanged) docs/concepts/cache.md 35ms (unchanged) docs/concepts/configuration-files.md 11ms (unchanged) docs/concepts/index.md 3ms (unchanged) docs/concepts/indexes.md 24ms (unchanged) docs/concepts/projects/build.md 5ms (unchanged) docs/concepts/projects/config.md 25ms (unchanged) docs/concepts/projects/dependencies.md 38ms (unchanged) docs/concepts/projects/index.md 3ms (unchanged) docs/concepts/projects/init.md 15ms (unchanged) docs/concepts/projects/layout.md 11ms (unchanged) docs/concepts/projects/run.md 7ms (unchanged) docs/concepts/projects/sync.md 15ms (unchanged) docs/concepts/projects/workspaces.md 15ms (unchanged) docs/concepts/python-versions.md 30ms (unchanged) docs/concepts/resolution.md 52ms (unchanged) docs/concepts/tools.md 20ms (unchanged) docs/getting-started/features.md 10ms (unchanged) docs/getting-started/first-steps.md 2ms (unchanged) docs/getting-started/help.md 5ms (unchanged) docs/getting-started/index.md 3ms (unchanged) docs/getting-started/installation.md 8ms (unchanged) docs/guides/index.md 2ms (unchanged) docs/guides/install-python.md 49ms (unchanged) docs/guides/integration/alternative-indexes.md 29ms (unchanged) docs/guides/integration/aws-lambda.md 102ms (unchanged) docs/guides/integration/dependency-bots.md 20ms (unchanged) docs/guides/integration/docker.md 38ms (unchanged) docs/guides/integration/fastapi.md 7ms (unchanged) docs/guides/integration/github.md 46ms (unchanged) docs/guides/integration/index.md 3ms (unchanged) docs/guides/integration/jupyter.md 16ms (unchanged) docs/guides/integration/marimo.md 6ms (unchanged) docs/guides/integration/pre-commit.md 14ms (unchanged) docs/guides/integration/pytorch.md 18ms (unchanged) docs/guides/package.md 9ms (unchanged) docs/guides/projects.md 11ms (unchanged) docs/guides/scripts.md 13ms (unchanged) docs/guides/tools.md 13ms (unchanged) docs/index.md 11ms (unchanged) docs/pip/compatibility.md 40ms (unchanged) docs/pip/compile.md 12ms (unchanged) docs/pip/dependencies.md 4ms (unchanged) docs/pip/environments.md 10ms (unchanged) docs/pip/index.md 4ms (unchanged) docs/pip/inspection.md 2ms (unchanged) docs/pip/packages.md 5ms (unchanged) docs/reference/benchmarks.md 2ms (unchanged) docs/reference/index.md 3ms (unchanged) docs/reference/installer.md 3ms (unchanged) docs/reference/policies/index.md 1ms (unchanged) docs/reference/policies/license.md 3ms (unchanged) docs/reference/policies/platforms.md 5ms (unchanged) docs/reference/policies/versioning.md 4ms (unchanged) docs/reference/resolver-internals.md 29ms (unchanged) docs/reference/troubleshooting/build-failures.md 19ms (unchanged) docs/reference/troubleshooting/index.md 2ms (unchanged) docs/reference/troubleshooting/reproducible-examples.md 9ms (unchanged) PIP_COMPATIBILITY.md 1ms (unchanged) README.md 15ms (unchanged) scripts/benchmark/README.md 1ms (unchanged) scripts/packages/built-by-uv/README.md 1ms (unchanged) scripts/packages/dependent_locals/first_local/README.md 0ms (unchanged) scripts/packages/dependent_locals/second_local/README.md 0ms (unchanged) scripts/packages/hatchling_editable/README.md 1ms (unchanged) scripts/packages/README.md 1ms (unchanged) scripts/packages/root_editable/README.md 0ms (unchanged) scripts/workspaces/albatross-virtual-workspace/packages/Unrelated.md 2ms (unchanged) SECURITY.md 3ms (unchanged) STYLE.md 16ms (unchanged) npm notice npm notice New minor version of npm available! 11.3.0 -> 11.4.2 npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.4.2 npm notice To update run: npm install -g npm@11.4.2 npm notice ➜ uv git:(docs/contributing-md-formatting) git status On branch docs/contributing-md-formatting nothing to commit, working tree clean ➜ uv git:(docs/contributing-md-formatting) ``` </details> Co-authored-by: Dmitry Bychkov <dbychkov@alarislabs.com>
195 lines
6.3 KiB
Markdown
195 lines
6.3 KiB
Markdown
# Contributing
|
|
|
|
We have issues labeled as
|
|
[Good First Issue](https://github.com/astral-sh/uv/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
|
|
and
|
|
[Help Wanted](https://github.com/astral-sh/uv/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
|
which are good opportunities for new contributors.
|
|
|
|
## Setup
|
|
|
|
[Rust](https://rustup.rs/) (and a C compiler) are required to build uv.
|
|
|
|
On Ubuntu and other Debian-based distributions, you can install a C compiler with:
|
|
|
|
```shell
|
|
sudo apt install build-essential
|
|
```
|
|
|
|
## Testing
|
|
|
|
For running tests, we recommend [nextest](https://nexte.st/).
|
|
|
|
If tests fail due to a mismatch in the JSON Schema, run: `cargo dev generate-json-schema`.
|
|
|
|
### Python
|
|
|
|
Testing uv requires multiple specific Python versions; they can be installed with:
|
|
|
|
```shell
|
|
cargo run python install
|
|
```
|
|
|
|
The storage directory can be configured with `UV_PYTHON_INSTALL_DIR`. (It must be an absolute path.)
|
|
|
|
### Snapshot testing
|
|
|
|
uv uses [insta](https://insta.rs/) for snapshot testing. It's recommended (but not necessary) to use
|
|
`cargo-insta` for a better snapshot review experience. See the
|
|
[installation guide](https://insta.rs/docs/cli/) for more information.
|
|
|
|
In tests, you can use `uv_snapshot!` macro to simplify creating snapshots for uv commands. For
|
|
example:
|
|
|
|
```rust
|
|
#[test]
|
|
fn test_add() {
|
|
let context = TestContext::new("3.12");
|
|
uv_snapshot!(context.filters(), context.add().arg("requests"), @"");
|
|
}
|
|
```
|
|
|
|
To run and review a specific snapshot test:
|
|
|
|
```shell
|
|
cargo test --package <package> --test <test> -- <test_name> -- --exact
|
|
cargo insta review
|
|
```
|
|
|
|
### Local testing
|
|
|
|
You can invoke your development version of uv with `cargo run -- <args>`. For example:
|
|
|
|
```shell
|
|
cargo run -- venv
|
|
cargo run -- pip install requests
|
|
```
|
|
|
|
## Running inside a Docker container
|
|
|
|
Source distributions can run arbitrary code on build and can make unwanted modifications to your
|
|
system
|
|
(["Someone's Been Messing With My Subnormals!" on Blogspot](https://moyix.blogspot.com/2022/09/someones-been-messing-with-my-subnormals.html),
|
|
["nvidia-pyindex" on PyPI](https://pypi.org/project/nvidia-pyindex/)), which can even occur when
|
|
just resolving requirements. To prevent this, there's a Docker container you can run commands in:
|
|
|
|
```console
|
|
$ docker build -t uv-builder -f crates/uv-dev/builder.dockerfile --load .
|
|
# Build for musl to avoid glibc errors, might not be required with your OS version
|
|
cargo build --target x86_64-unknown-linux-musl --profile profiling
|
|
docker run --rm -it -v $(pwd):/app uv-builder /app/target/x86_64-unknown-linux-musl/profiling/uv-dev resolve-many --cache-dir /app/cache-docker /app/scripts/popular_packages/pypi_10k_most_dependents.txt
|
|
```
|
|
|
|
We recommend using this container if you don't trust the dependency tree of the package(s) you are
|
|
trying to resolve or install.
|
|
|
|
## Profiling and Benchmarking
|
|
|
|
Please refer to Ruff's
|
|
[Profiling Guide](https://github.com/astral-sh/ruff/blob/main/CONTRIBUTING.md#profiling-projects),
|
|
it applies to uv, too.
|
|
|
|
We provide diverse sets of requirements for testing and benchmarking the resolver in
|
|
`scripts/requirements` and for the installer in `scripts/requirements/compiled`.
|
|
|
|
You can use `scripts/benchmark` to benchmark predefined workloads between uv versions and with other
|
|
tools, e.g., from the `scripts/benchmark` directory:
|
|
|
|
```shell
|
|
uv run resolver \
|
|
--uv-pip \
|
|
--poetry \
|
|
--benchmark \
|
|
resolve-cold \
|
|
../scripts/requirements/trio.in
|
|
```
|
|
|
|
### Analyzing concurrency
|
|
|
|
You can use [tracing-durations-export](https://github.com/konstin/tracing-durations-export) to
|
|
visualize parallel requests and find any spots where uv is CPU-bound. Example usage, with `uv` and
|
|
`uv-dev` respectively:
|
|
|
|
```shell
|
|
RUST_LOG=uv=info TRACING_DURATIONS_FILE=target/traces/jupyter.ndjson cargo run --features tracing-durations-export --profile profiling -- pip compile scripts/requirements/jupyter.in
|
|
```
|
|
|
|
```shell
|
|
RUST_LOG=uv=info TRACING_DURATIONS_FILE=target/traces/jupyter.ndjson cargo run --features tracing-durations-export --bin uv-dev --profile profiling -- resolve jupyter
|
|
```
|
|
|
|
### Trace-level logging
|
|
|
|
You can enable `trace` level logging using the `RUST_LOG` environment variable, i.e.
|
|
|
|
```shell
|
|
RUST_LOG=trace uv
|
|
```
|
|
|
|
## Documentation
|
|
|
|
To preview any changes to the documentation locally:
|
|
|
|
1. Install the [Rust toolchain](https://www.rust-lang.org/tools/install).
|
|
|
|
2. Run `cargo dev generate-all`, to update any auto-generated documentation.
|
|
|
|
3. Run the development server with:
|
|
|
|
```shell
|
|
# For contributors.
|
|
uvx --with-requirements docs/requirements.txt -- mkdocs serve -f mkdocs.public.yml
|
|
|
|
# For members of the Astral org, which has access to MkDocs Insiders via sponsorship.
|
|
uvx --with-requirements docs/requirements-insiders.txt -- mkdocs serve -f mkdocs.insiders.yml
|
|
```
|
|
|
|
The documentation should then be available locally at
|
|
[http://127.0.0.1:8000/uv/](http://127.0.0.1:8000/uv/).
|
|
|
|
To update the documentation dependencies, edit `docs/requirements.in` and
|
|
`docs/requirements-insiders.in`, then run:
|
|
|
|
```shell
|
|
uv pip compile docs/requirements.in -o docs/requirements.txt --universal -p 3.12
|
|
uv pip compile docs/requirements-insiders.in -o docs/requirements-insiders.txt --universal -p 3.12
|
|
```
|
|
|
|
Documentation is deployed automatically on release by publishing to the
|
|
[Astral documentation](https://github.com/astral-sh/docs) repository, which itself deploys via
|
|
Cloudflare Pages.
|
|
|
|
After making changes to the documentation, format the markdown files with:
|
|
|
|
```shell
|
|
npx prettier --prose-wrap always --write "**/*.md"
|
|
```
|
|
|
|
Note that the command above requires Node.js and npm to be installed on your system. As an
|
|
alternative, you can run this command using Docker:
|
|
|
|
```console
|
|
$ docker run --rm -v .:/src/ -w /src/ node:alpine npx prettier --prose-wrap always --write "**/*.md"
|
|
```
|
|
|
|
## Releases
|
|
|
|
Releases can only be performed by Astral team members.
|
|
|
|
Changelog entries and version bumps are automated. First, run:
|
|
|
|
```shell
|
|
./scripts/release.sh
|
|
```
|
|
|
|
Then, editorialize the `CHANGELOG.md` file to ensure entries are consistently styled.
|
|
|
|
Then, open a pull request, e.g., `Bump version to ...`.
|
|
|
|
Binary builds will automatically be tested for the release.
|
|
|
|
After merging the pull request, run the
|
|
[release workflow](https://github.com/astral-sh/uv/actions/workflows/release.yml) with the version
|
|
tag. **Do not include a leading `v`**. The release will automatically be created on GitHub after
|
|
everything else publishes.
|