Files
uv/CONTRIBUTING.md
Charlie Marsh c3d809d276 Migrate to zlib-rs (again) (#11894)
## Summary

I believe `zlib-rs` is now a better choice on ARM and x86, so I'm just
going to assume it's a better choice everywhere. It's much easier to
build (removes our CMake dependency), and in my benchmarking, it's
substantially faster on ARM and faster or ~exactly even on my x86
Windows machine.

We migrated to `zlib-rs` once before (#9184); however, I later reverted
it as I learned that they were only doing compile-time feature
detection, and so `zlib-rs` was meaningfully slower on x86. They now
perform runtime feature detection:
https://trifectatech.org/blog/zlib-rs-is-faster-than-c/.

To benchmark, I wrote a script to create a local Simple API-compliant
registry (see the commit history) for a single package. Then I ran the
`install-cold` benchmark against that registry to install NumPy.

On ARM:

```
❯ uv run resolver --uv-pip-path ../../zlib-ng --uv-pip-path ../../zlib-rs \
        --benchmark install-cold \
        req.txt --warmup 10 --min-runs 30
Benchmark 1: ../../zlib-ng (install-cold)
  Time (mean ± σ):     165.7 ms ±  34.7 ms    [User: 64.4 ms, System: 93.2 ms]
  Range (min … max):   141.8 ms … 293.2 ms    30 runs

Benchmark 2: ../../zlib-rs (install-cold)
  Time (mean ± σ):     150.9 ms ±  16.2 ms    [User: 57.4 ms, System: 86.4 ms]
  Range (min … max):   135.3 ms … 202.4 ms    30 runs

Summary
  ../../zlib-rs (install-cold) ran
    1.10 ± 0.26 times faster than ../../zlib-ng (install-cold)
```

I benchmarked this about 100 times on my Windows machine and found it
difficult to conclude anything beyond "They're nearly the same". Here's
an example:

```
PS C:\Users\crmar\workspace\puffin> hyperfine --prepare "uv venv" "zlib-rs.exe pip sync ./scripts/benchmark/req.txt" "zlib-ng.exe pip sync ./scripts/benchmark/req.txt" "zlib-rs.exe pip sync ./scripts/benchmark/req.txt" "zlib-ng.exe pip sync ./scripts/benchmark/req.txt" --runs 10 --warmup 5
Benchmark 1: zlib-rs.exe pip sync ./scripts/benchmark/req.txt
  Time (mean ± σ):     240.6 ms ±  10.8 ms    [User: 6.1 ms, System: 92.2 ms]
  Range (min … max):   229.4 ms … 267.9 ms    10 runs

Benchmark 2: zlib-ng.exe pip sync ./scripts/benchmark/req.txt
  Time (mean ± σ):     241.3 ms ±   6.2 ms    [User: 7.7 ms, System: 90.6 ms]
  Range (min … max):   233.9 ms … 252.1 ms    10 runs

Benchmark 3: zlib-rs.exe pip sync ./scripts/benchmark/req.txt
  Time (mean ± σ):     242.8 ms ±   7.7 ms    [User: 6.2 ms, System: 23.4 ms]
  Range (min … max):   236.1 ms … 262.8 ms    10 runs

Benchmark 4: zlib-ng.exe pip sync ./scripts/benchmark/req.txt
  Time (mean ± σ):     245.9 ms ±   5.7 ms    [User: 1.5 ms, System: 59.4 ms]
  Range (min … max):   240.9 ms … 257.3 ms    10 runs

Summary
  zlib-rs.exe pip sync ./scripts/benchmark/req.txt ran
    1.00 ± 0.05 times faster than zlib-ng.exe pip sync ./scripts/benchmark/req.txt
    1.01 ± 0.06 times faster than zlib-rs.exe pip sync ./scripts/benchmark/req.txt
    1.02 ± 0.05 times faster than zlib-ng.exe pip sync ./scripts/benchmark/req.txt
```

Closes #11885.
2025-03-03 17:29:31 +00:00

188 lines
6.0 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 buildx build -t uv-builder -f 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"
```
## 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.