Commit Graph

277 Commits

Author SHA1 Message Date
Charlie Marsh bd9c365b92
Support `--find-links`-style "flat" indexes in `[[tool.uv.index]]` (#12407)
## Summary

This PR extends `[[tool.uv.index]]` to support `--find-links`-style
"flat" indexes, so that users can point to such indexes without using
`--find-links` _and_ get access to the full functionality of
`[[tool.uv.index]]` (e.g., they can now pin packages to
`--find-links`-style indexes).

Note that, at present, `--find-links` indexes actually have some quirky
behavior, in that we combine them into a single entity and then merge
the discovered distributions into each Simple API-style index. The
motivation here, IIRC, was to match pip's behavior quite closely. I'm
interested in _removing_ that behavior, but it'd be breaking (and may
also be inconvenient for some use-cases). So, the behavior for indexes
passed in via `--find-links` remains completely unchanged. However,
`[[tool.uv.index]]` entries with `format = "flat"` are now treated
identically to those defined with `format = "simple"` (the default), in
that we stop after we find the first-matching index, etc.

Closes https://github.com/astral-sh/uv/issues/11634.
2025-03-25 21:14:44 -04:00
Charlie Marsh e4c98e976f
Use `Box<Path>` in lieu of `PathBuf` for immutable structs (#12346)
## Summary

I don't know if I actually want to commit this, but I did it on the
plane last time and just polished it off (got it to compile) while
waiting to board.
2025-03-25 21:56:06 +00:00
Charlie Marsh 1865e0a6ee
Pass around index with associated metadata (#12406)
## Summary

This PR modifies the requirement source entities to store a (new)
container struct that wraps `IndexUrl`. This will allow us to store
user-defined metadata alongside `IndexUrl`, and propagate that metadata
throughout resolution.

Specifically, I need to store the "kind" of the index (Simple API vs.
`--find-links`), but I also ran into this problem when I tried to add
support for overriding `Cache-Control` headers on a per-index basis: at
present, we have no way to passing around metadata alongside an
`IndexUrl`.
2025-03-24 10:15:49 -04:00
Charlie Marsh 9af989e30c
Extract a single-index fetch in flat index client (#12394) 2025-03-23 09:07:19 -04:00
Charlie Marsh bbf4f830b5
Remove flat index client's dependency on registry client (#12393)
## Summary

I want to use the flat index client from within the registry client, so
making them both depend on the same underlying primitives rather than
having the flat index client depend on the registry client.
2025-03-22 18:14:25 +00:00
Charlie Marsh 4215d0e16b
Check all compatible torch indexes when `--torch-backend` is enabled (#12385)
## Summary

It's possible that the PyTorch version the user depends on isn't in the
latest index. These indexes are equally trusted, so we should override
the policy.

Closes #12357.
2025-03-22 11:53:23 -04:00
Charlie Marsh 59c6d34b59
Omit fragment when querying for wheels in Simple HTML API (#12384)
## Summary

Closes https://github.com/astral-sh/uv/issues/12383.
2025-03-22 11:36:50 -04:00
Charlie Marsh 5173b59b50
Automatically infer the PyTorch index via `--torch-backend=auto` (#12070)
## Summary

This is a prototype that I'm considering shipping under `--preview`,
based on [`light-the-torch`](https://github.com/pmeier/light-the-torch).

`light-the-torch` patches pip to pull PyTorch packages from the PyTorch
indexes automatically. And, in particular, `light-the-torch` will query
the installed CUDA drivers to determine which indexes are compatible
with your system.

This PR implements equivalent behavior under `--torch-backend auto`,
though you can also set `--torch-backend cpu`, etc. for convenience.
When enabled, the registry client will fetch from the appropriate
PyTorch index when it sees a package from the PyTorch ecosystem (and
ignore any other configured indexes, _unless_ the package is explicitly
pinned to a different index).

Right now, this is only implemented in the `uv pip` CLI, since it
doesn't quite fit into the lockfile APIs given that it relies on feature
detection on the currently-running machine.

## Test Plan

On macOS, you can test this with (e.g.):

```shell
UV_TORCH_BACKEND=auto UV_CUDA_DRIVER_VERSION=450.80.2 cargo run \
  pip install torch --python-platform linux --python-version 3.12
```

On a GPU-enabled EC2 machine:

```shell
ubuntu@ip-172-31-47-149:~/uv$ UV_TORCH_BACKEND=auto cargo run pip install torch -v
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
     Running `target/debug/uv pip install torch -v`
DEBUG uv 0.6.6 (e95ca063b 2025-03-14)
DEBUG Searching for default Python interpreter in virtual environments
DEBUG Found `cpython-3.13.0-linux-x86_64-gnu` at `/home/ubuntu/uv/.venv/bin/python3` (virtual environment)
DEBUG Using Python 3.13.0 environment at: .venv
DEBUG Acquired lock for `.venv`
DEBUG At least one requirement is not satisfied: torch
warning: The `--torch-backend` setting is experimental and may change without warning. Pass `--preview` to disable this warning.
DEBUG Detected CUDA driver version from `/sys/module/nvidia/version`: 550.144.3
...
```
2025-03-19 14:37:08 +00:00
Charlie Marsh 72be5ffb25
Always reinstall local source trees passed to `uv pip install` (#12176)
## Summary

This ended up being more involved than expected. The gist is that we
setup all the packages we want to reinstall upfront (they're passed in
on the command-line); but at that point, we don't have names for all the
packages that the user has specified. (Consider, e.g., `uv pip install
.` -- we don't have a name for `.`, so we can't add it to the list of
`Reinstall` packages.)

Now, `Reinstall` also accepts paths, so we can augment `Reinstall` based
on the user-provided paths.

Closes #12038.
2025-03-17 21:12:21 +00:00
James Z.M. Gao 05352882ea
make BaseClientBuild accept custom proxies (#12232)
close #12230 

implement `BaseClientBuilder::proxy(self, Proxy)` and apply it to the
underlying reqwest::Client.
2025-03-17 14:18:55 -05:00
Charlie Marsh d2b9ffdc9e
Avoid replicating core-metadata field on `File` struct (#12159)
## Summary

A long-standing TODO: we don't need to store three copies of this just
to ensure that Serde considers all three fields.
2025-03-14 10:03:09 -04:00
James Z.M. Gao 7fc4e076c1
remove `BaseClientBuild::client`, expose `ExtraMiddleware` (#12133)
close #12127 

as discussed in #12127 remove unused BaseClientBuild::client field, and
make base_client::ExtraMiddleware public.
2025-03-12 10:43:21 +00:00
John Mumm c58675fdac
Add an optional authentication policy to [index] configuration (#11896)
Adds a new optional key `auth-policy` to `[tool.uv.index]` that sets the
authentication policy for the index URL.

The default is `"auto"`, which attempts to authenticate when necessary.
`"always"` always attempts to authenticate and fails if the endpoint is
unauthenticated. `"never"` never attempts to authenticate.

These policy address two kinds of cases:
* Some indexes don’t fail on unauthenticated requests; instead they just
forward to the public PyPI. This can leave the user confused as to why
their package is missing. The "always" policy prevents this.
* "never" allows users to ensure their credentials couldn't be leaked to
an unexpected index, though it will only allow for successful requests
on an index that doesn't require credentials.

Closes #11600
2025-03-10 12:24:25 -05:00
Ankit Saini fb35875f24
Use hash instead of full wheel name in wheels bucket (#11738)
<!--
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
Closes #2410 
<!-- What's the purpose of the change? What does it do, and why? -->
This changes the name of files in `wheels` bucket to use a hash instead
of the wheel name as to not exceed maximum file length limit on various
systems.

This only addresses the primary concern of #2410. It still does _not_
address:
- Path limit of 260 on windows:
https://github.com/astral-sh/uv/issues/2410#issuecomment-2062020882
To solve this we need to opt-in to longer path limits on windows
([ref](https://github.com/astral-sh/uv/issues/2410#issuecomment-2150532658)),
but I think that is a separate issue and should be a separate MR.
- Exceeding filename limit while building a wheel from source
distribution
As per my understanding, this is out of uv's control. Name of the output
wheel will be decided by build-backend used by the project. For wheels
built from source distribution, pip also uses the wheel names in cache.
So I have not touched `sdists` cache.


I have added a `filename: WheelFileName` field in `Archive`, so we can
use it while indexing instead of relying on the filename on disk.
Another way to do this was to read `.dist-info/WHEEL` and
`.dist-info/METADATA` and build `WheelFileName` but that seems less
robust and will be slower.
## Test Plan

<!-- How was it tested? -->
Tested by installing `yt-dlp`, `httpie` and `sqlalchemy` and verifying
that cache files in `wheels` bucket use hash.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2025-02-26 22:41:57 +00:00
Charlie Marsh 275db0668d
Use `SmallString` for filenames and URLs (#11765)
## Summary

These are never mutated, so there's no need to store them as `String`.
2025-02-24 23:06:57 -08:00
Charlie Marsh d9adba1cf5
Use a `Box` for `Yanked` on `File` (#11755)
## Summary

See: https://github.com/astral-sh/uv/pull/11715.
2025-02-24 09:46:14 -10:00
Charlie Marsh 4fc181dbf2
Use a `SmallString` for the Yanked enum (#11715)
## Summary

This is stored on `File`, which we create extensively. Easy way to
reduce size.
2025-02-24 09:03:56 -10:00
Charlie Marsh 21f4b0863d
Use boxed slices for hash vector (#11714)
## Summary

We never resize these, and they're stored everywhere (on `File`, etc.).
Seems useful to use a more efficient structure for them.
2025-02-24 11:11:44 -06:00
samypr100 878497a014
Upgrade Rust toolchain to 1.85 (#11720)
## Summary

* Upgrade the rust toolchain to 1.85.0. This does not increase the MSRV.
* Update windows trampoline to 1.86 nightly beta (previously in 1.85
nightly beta).

## Test Plan

Existing tests
2025-02-23 16:52:34 +01:00
Zanie Blue 346e6b7e8b
Fallback to `GET` on HTTP 400 when attempting to use range requests for wheel download (#11539)
See https://github.com/astral-sh/uv/issues/11501
2025-02-15 22:02:46 -06:00
Charlie Marsh 5d8168875a
Ignore 'egg' fragment in HTML Simple API response (#11340)
## Summary

Closes https://github.com/astral-sh/uv/issues/11339.
2025-02-08 09:00:51 -05:00
Charlie Marsh 748582ee6f
Disable SSL in Git commands for `--allow-insecure-host` (#11210)
## Summary

Closes https://github.com/astral-sh/uv/issues/11176.

## Test Plan

- Created a self-signed certificate.
- Ran `openssl s_server -cert cert.pem -key key.pem -WWW -port 8443`.
- Verified that `cargo run pip install
git+https://localhost:8443/repo.git` failed with:

```
error: Git operation failed
  Caused by: failed to fetch into: /Users/crmarsh/.cache/uv/git-v0/db/0773914b3ec4a56e
  Caused by: process didn't exit successfully: `/usr/bin/git fetch --force --update-head-ok 'https://localhost:8443/repo.git' '+HEAD:refs/remotes/origin/HEAD'` (exit status: 128)
--- stderr
fatal: unable to access 'https://localhost:8443/repo.git/': SSL certificate problem: self signed certificate
```

- Verified that `cargo run pip install
git+https://localhost:8443/repo.git --allow-insecure-host
https://localhost:8443` continued further.
2025-02-04 10:57:57 -05:00
konsti 56684e4c24
Respect concurrency limits in parallel index fetch (#11182)
With the parallel simple index fetching, we would only acquire one
download concurrency token, meaning that we could in the worst case make
times the number of indexes more requests than the user requested limit.
We fix this by passing the semaphore down to the simple API method.
2025-02-03 16:41:17 +01:00
Charlie Marsh 8adf4a8977
Migrate from `urlencoding` to `percent-encoding` (#11144)
## Summary

This lets us drop a dependency entirely. `percent-encoding` is used by
`url` and so is already in the graph, whereas `urlencoding` isn't used
by anything else.
2025-01-31 16:29:46 -05:00
Zanie Blue 5c0fdfd7ce
Consistently write log messages with capitalized first word (#11111) 2025-01-30 18:56:46 +00:00
Charlie Marsh ee31e1f11b
Remove unnecessary UTF-8 conversion in hash parsing (#11110)
## Summary

I believe this is a no-op?
2025-01-30 13:55:46 -05:00
Zanie Blue d514743b1a
Improve retry trace message (#11108) 2025-01-30 12:53:33 -06:00
Charlie Marsh a440735fac
Ignore non-hash fragments in HTML API responses (#11107)
## Summary

I'm not a fan of registries including fragments here that aren't hashes,
but the spec doesn't expressly forbid it. I think it's reasonable to
ignore them.

Specifically, the spec is here:
https://packaging.python.org/en/latest/specifications/simple-repository-api/.
It says that:

> The URL **SHOULD** include a hash in the form of a URL fragment with
the following syntax: `#<hashname>=<hashvalue>`, where `<hashname>`he
lowercase name of the hash function (such as sha256) and `<hashvalue>`
is the hex encoded digest.

But it doesn't mention other fragments.

Closes https://github.com/astral-sh/uv/issues/7257.
2025-01-30 12:35:11 -06:00
Charlie Marsh 329de04758
Use a mirror with upload timestamps for PyTorch (#11086)
## Summary

This PR migrates all of our PyTorch tests to use our own mirror, which
includes upload timestamps that we can use to enforce
`--excludes-newer`, making the tests far more stable over time. (Today,
if you checkout old versions of `uv`, many of the PyTorch tests will
fail, since the index contents drift over time.)

Some snapshots changed in this PR (see, e.g.,
`universal_nested_overlapping_local_requirement`). The underlying reason
is that I used the current timestamp when setting upload times in the
PyTorch mirror, but those tests read from both the PyTorch
`--find-links` index _and_ PyPI. I guess we don't omit `--find-links`
entries based on `--excludes-newer`? That might be a bug. But I had to
_increase_ the `--excludes-newer` to include the PyTorch mirror's
`--find-links`, which meant pulling in some newer packages from PyPI
too. This is fine: it's a one-time churn, and they'll be stable going
forward.
2025-01-29 20:02:30 -05:00
Charlie Marsh f1840c77b6
Guard against concurrent cache writes on Windows (#11007)
## Summary

On Windows, we have a lot of issues with atomic replacement and such.
There are a bunch of different failure modes, but they generally
involve: trying to persist a fail to a path at which the file already
exists, trying to replace or remove a file while someone else is reading
it, etc.

This PR adds locks to all of the relevant database paths. We already use
these advisory locks when building source distributions; now we use them
when unzipping wheels, storing metadata, etc.

Closes #11002.

## Test Plan

I ran the following script:

```shell
# Define the cache directory path
$cacheDir = "C:\Users\crmar\workspace\uv\cache"

# Clear the cache directory if it exists
if (Test-Path $cacheDir) {
    Remove-Item -Recurse -Force $cacheDir
}

# Create the cache directory again
New-Item -ItemType Directory -Force -Path $cacheDir

# Define the command to run with --cache-dir flag
$command = {
    param ($venvPath)

    # Create a virtual environment in the specified path with --python
    uv venv $venvPath

    # Run the pip install command with --cache-dir flag
    C:\Users\crmar\workspace\uv\target\profiling\uv.exe pip install flask==1.0.4 --no-binary flask --cache-dir C:\Users\crmar\workspace\uv\cache -v --python $venvPath
}

# Define the paths for the different virtual environments
$venv1 = "C:\Users\crmar\workspace\uv\venv1"
$venv2 = "C:\Users\crmar\workspace\uv\venv2"
$venv3 = "C:\Users\crmar\workspace\uv\venv3"
$venv4 = "C:\Users\crmar\workspace\uv\venv4"
$venv5 = "C:\Users\crmar\workspace\uv\venv5"

# Start the command in parallel five times using Start-Job, each with a different venv
$job1 = Start-Job -ScriptBlock $command -ArgumentList $venv1
$job2 = Start-Job -ScriptBlock $command -ArgumentList $venv2
$job3 = Start-Job -ScriptBlock $command -ArgumentList $venv3
$job4 = Start-Job -ScriptBlock $command -ArgumentList $venv4
$job5 = Start-Job -ScriptBlock $command -ArgumentList $venv5

# Wait for all jobs to complete
$jobs = @($job1, $job2, $job3, $job4, $job5)
$jobs | ForEach-Object { Wait-Job $_ }

# Retrieve the results (optional)
$jobs | ForEach-Object { Receive-Job -Job $_ }

# Clean up the jobs
$jobs | ForEach-Object { Remove-Job -Job $_ }
```

And ensured it succeeded in five straight invocations (whereas on
`main`, it consistently fails with a variety of different traces).
2025-01-28 15:33:49 -05:00
Charlie Marsh c306e46e1d
Remove trailing commas before brackets (#10740) 2025-01-18 19:56:46 +00:00
Charlie Marsh 325b060829
Recommend `--native-tls` on SSL errors (#10605)
## Summary

Closes https://github.com/astral-sh/uv/issues/10574.

## Test Plan

```
❯ SSL_CERT_FILE=a cargo run pip install flask -n
   Compiling uv v0.5.18 (/Users/crmarsh/workspace/uv/crates/uv)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.33s
     Running `target/debug/uv pip install flask -n`
⠦ Resolving dependencies...                                                                                                                                                                                                                     × Failed to fetch: `https://pypi.org/simple/flask/`
  ├─▶ Request failed after 3 retries
  ├─▶ error sending request for url (https://pypi.org/simple/flask/)
  ├─▶ client error (Connect)
  ╰─▶ invalid peer certificate: UnknownIssuer
  help: Consider enabling native TLS support via the `--native-tls` command-line flag
```
2025-01-14 13:17:19 -05:00
Charlie Marsh c5e536f0ec
De-duplicate result handling in Simple API responses (#10449)
## Summary

See: https://github.com/astral-sh/uv/pull/10432#issuecomment-2581084234
2025-01-09 22:45:13 +00:00
Charlie Marsh a0494bb059
Fetch concurrently for non-first-match index strategies (#10432)
## Summary

On a basic test, this speeds up cold resolution by about 25%:

```
❯ hyperfine "uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache" "../target/release/uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache" --warmup 10 --runs 30
Benchmark 1: uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache
  Time (mean ± σ):     585.8 ms ±  28.2 ms    [User: 149.7 ms, System: 97.4 ms]
  Range (min … max):   541.5 ms … 654.8 ms    30 runs

Benchmark 2: ../target/release/uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache
  Time (mean ± σ):     468.3 ms ±  52.0 ms    [User: 131.7 ms, System: 76.9 ms]
  Range (min … max):   380.2 ms … 607.0 ms    30 runs

Summary
  ../target/release/uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache ran
    1.25 ± 0.15 times faster than uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache
```

Given:
```toml
[project]
name = "foo"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12.0"
dependencies = [
    "black>=24.10.0",
    "django>=5.1.4",
    "flask>=3.1.0",
    "requests>=2.32.3",
]
```

And:

```shell
hyperfine "uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache" "../target/release/uv lock --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --upgrade --no-cache" --warmup 10 --runs 30
```

Closes https://github.com/astral-sh/uv/issues/10429.
2025-01-09 12:45:20 -05:00
konsti c5583b326f
Shrink `Dist` from 352 to 288 bytes (#10389)
Found this when looking at #10385. Since we're constructing a lot of
`Dist`s, we should keep it small.
2025-01-08 09:33:19 -05:00
konsti a1a4d820d5
Add `Send + 'static` bounds to cache deserialization (#10352) 2025-01-07 09:55:37 +00:00
Charlie Marsh 5b334313e5
Visit source distributions before wheels (#10291)
## Summary

This should address the comment here:
https://github.com/astral-sh/uv/pull/10179#issuecomment-2569189265. We
don't compute implied markers if the marker is already `TRUE`, and we
set it to `TRUE` as soon as we see a source distribution. So if we visit
the source distribution before the wheels, we'll avoid computing these
for any irrelevant distributions.
2025-01-03 12:07:29 -05:00
Charlie Marsh 906511fa23
Ignore empty or missing hrefs in Simple HTML (#10276)
## Summary

Closes https://github.com/astral-sh/uv/issues/7735.

## Test Plan

`cargo run pip install -f https://whl.smartgic.io/ ggwave
--python-platform linux` (fails prior to this PR; passes after)
2025-01-02 17:43:15 +00:00
Charlie Marsh 7bbec6b2e4
Parse URLs lazily in resolver (#10259)
## Summary

The idea here is to avoid parsing all registry URLs upfront, and instead
parse them when we need them.

Closes #6133.
2025-01-01 12:35:30 -05:00
Charlie Marsh bec8468183
Remove unnecessary prefixes (#10158) 2024-12-25 14:18:01 -05:00
Zanie Blue ae25c2f4db
Upgrade minimum Rust version to 1.83 (#9815)
This reverts commit 6cc7a560f7 to reapply
#9511 since we've disabled ppc64le-musl per #9793
2024-12-11 10:06:19 -06:00
Charlie Marsh eb21e4bd25
Retry on tar extraction errors (#9753)
## Summary

So the error here is:

```rust
ExtractError("cpython-3.11.11%2B20241206-aarch64-apple-darwin-install_only_stripped.tar.gz", Io(Custom { kind: UnexpectedEof, error: TarError { desc: "failed to unpack `/Users/crmarsh/.local/share/uv/python/.cache/.tmpkqFzqE/python/lib/libpython3.11.dylib`", io: Custom { kind: UnexpectedEof, error: TarError { desc: "failed to unpack `python/lib/libpython3.11.dylib` into `/Users/crmarsh/.local/share/uv/python/.cache/.tmpkqFzqE/python/lib/libpython3.11.dylib`", io: Custom { kind: UnexpectedEof, error: "unexpected end of file" } } } } }))
```

This isn't a Reqwest error, so we miss it in
`is_extended_transient_error`.

We could add `TarError` or `ExtractError` here, but... should we? This
PR just extends it to any error that has an IO source. I don't see much
of a downside.

Closes https://github.com/astral-sh/uv/issues/9747.

## Test Plan

First, ran: `uv run ./scripts/create-python-mirror.py --name cpython
--arch aarch64 --os darwin`.

Then, dropped this into `./scripts/mirror/server.py`:

```python
import os
import random
from http.server import SimpleHTTPRequestHandler, HTTPServer


class GlitchyStaticServer(SimpleHTTPRequestHandler):
    def do_GET(self):
        """Handle GET request."""
        file_path = self.translate_path(self.path)
        
        if not os.path.exists(file_path):
            self.send_error(404, "File not found")
            return
        
        try:
            with open(file_path, 'rb') as f:
                file_content = f.read()

            # Introduce an "unexpected end of file" glitch randomly
            if random.random() < 0.75:  # 75% chance of glitch
                glitch_point = random.randint(1, len(file_content) - 1)
                file_content = file_content[:glitch_point]

            self.send_response(200)
            self.send_header("Content-type", self.guess_type(file_path))
            self.send_header("Content-Length", len(file_content))
            self.end_headers()
            self.wfile.write(file_content)
        
        except Exception as e:
            self.send_error(500, f"Internal Server Error: {e}")
        

def run(server_class=HTTPServer, handler_class=GlitchyStaticServer, port=8080):
    """Run the server."""
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print(f"Serving on port {port} with glitchy behavior")
    httpd.serve_forever()


if __name__ == "__main__":
    run()
```

Then ran `python server.py` from that directory.

From there, ran `UV_PYTHON_INSTALL_MIRROR="http://localhost:8080" cargo
run python install 3.11 --reinstall --verbose` to reliably test retries.
2024-12-10 07:33:08 -05:00
Charlie Marsh 1dc0276458
Avoid treating non-existent `--find-links` as relative URLs (#9720)
## Summary

Closes https://github.com/astral-sh/uv/issues/9681.
2024-12-08 12:22:18 -05:00
Charlie Marsh 3aaa9594be
Add test coverage for build tag prioritization (#9680)
## Summary

See: https://github.com/astral-sh/uv/pull/3781 and
https://github.com/astral-sh/uv/pull/9677.
2024-12-06 09:32:19 -05:00
Zanie Blue 6cc7a560f7
Revert "Upgrade to Rust 1.83 (#9511)" (#9617)
This reverts commit cf20673197 (#9511) due
to failure on powerpc64le in https://github.com/astral-sh/uv/pull/9612
2024-12-03 19:21:05 +00:00
Charlie Marsh cf20673197
Upgrade to Rust 1.83 (#9511)
## Summary

A lot of good new lints, and most importantly, error stabilizations. I
tried to find a few usages of the new stabilizations, but I'm sure there
are more.

IIUC, this _does_ require bumping our MSRV.
2024-11-29 12:04:22 -05:00
Charlie Marsh 1b13036674
Add retries for Python downloads (#9274)
## Summary

This uses the same approach as in the rest of uv, but with another
dedicated method for retries.

Closes https://github.com/astral-sh/uv/issues/8525.
2024-11-20 09:42:42 -05:00
Zanie Blue 7c4c15b879
Add trace logs to `is_extended_transient_error` (#9248)
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-11-19 22:24:05 -05:00
Charlie Marsh 9fb7f81738
Catch retries with wrapped `reqwest` errors (#9253)
## Summary

It turns out that `WrappedReqwestError` skips the `reqwest::Error`
itself in order to hack the display. This PR adds it to the list of
variants we check when retrying transient errors.

Closes https://github.com/astral-sh/uv/issues/9246.


## Test Plan

Patched `reqwest` locally to return an error in `bytes()`. Verified that
it was _not_ caught prior to this PR, but was caught afterwards.
2024-11-19 17:08:48 -05:00
konsti 0913382aa5
Better WrappedReqwestError docs (#9251)
Document the hack with which we insert a hint message for offline cases.
2024-11-19 16:51:58 -05:00
Charlie Marsh 821f3de095
Automatically retry body errors when processing response (#9213)
## Summary

The reqwest middleware doesn't retry errors that occur "after" the
request completes -- but in some cases, these do include spurious errors
that we want to retry. See https://github.com/astral-sh/uv/issues/8144
for examples. This PR adds a second retry layer during the response
_handler_, which should help with some of the spurious failures we see
in the linked issue.

Closes https://github.com/astral-sh/uv/issues/8144.
2024-11-19 04:14:58 +00:00
Charlie Marsh d08bfee718
Remove separate test files in favor of same-file `mod tests` (#9199)
## Summary

These were moved as part of a broader refactor to create a single
integration test module. That "single integration test module" did
indeed have a big impact on compile times, which is great! But we aren't
seeing any benefit from moving these tests into their own files (despite
the claim in [this blog
post](https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html),
I see the same compilation pattern regardless of where the tests are
located). Plus, we don't have many of these, and same-file tests is such
a strong Rust convention.
2024-11-18 20:11:46 +00:00
konsti 57ff5330fc
Show link we failed on parsing index pages (#9118)
For #8172, show the link we failed on. This should e.g. give a hint on
permission denied pages such as
https://github.com/astral-sh/uv/issues/8172#issuecomment-2474392691.
2024-11-14 16:00:33 +01:00
Tim de Jager d82607d038
Extend BaseClient to accept extra middleware (#8807)
This PR is a revival of #3502, albeit in a much simpler form.

This would allow for different middlewares like authentication and such,
useful for if you want to deviate from the keychain authentication
methods when using uv as a library.

@zanieb I hope I made the changes as you noted you wanted to see them :)

Happy to add/change anything you need.
2024-11-04 07:04:26 -06:00
Andrew Gallant 049ccf7d77
uv-client: switch to RFC 9110 compatible format (#8752)
This still utilizes the RFC 2822 datetime formatter, but utilizes new
methods [added in jiff 0.1.14] to emit timestamps in a format strictly
compatible with RFC 9110.

It seems like most HTTP servers were pretty flexible and supported RFC
2822 datetime formats, but #8747 shows at least one case where that
isn't true. Given that the [MDN docs prescribe RFC 9110], we defer to
them.

Fixes #8747

[added in jiff 0.1.14]: https://github.com/BurntSushi/jiff/pull/154
[MDN docs prescribe RFC 9110]:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since
2024-11-01 09:46:24 -04:00
konsti 082259493e
Skip existing, second iteration: Check the index before uploading (#8531)
Co-authored-by: Zanie Blue <contact@zanie.dev>
2024-10-31 16:23:12 +01:00
konsti 3eda248ef5
Always attach URL to network errors (#8444) 2024-10-25 09:10:18 +00:00
konsti e7ae0f50d2
Respect allow insecure host in publish (#8440) 2024-10-22 13:36:18 +02:00
konsti 7eed0bcd23
Add more context on resolve client error (#8285)
I'm not clear where #8144 comes from, so I'm adding some more error
context to narrow it down.
2024-10-17 08:22:09 -04:00
Charlie Marsh 4ca158931a
Show hint in resolution failure on `Forbidden` (`403`) or `Unauthorized` (`401`) (#8264)
## Summary

Closes https://github.com/astral-sh/uv/issues/8167.
2024-10-16 17:34:29 +00:00
Charlie Marsh a034a8b83b
Remove the flat index types (#7759)
## Summary

I think these really don't pull their weight.
2024-10-15 23:30:37 +00:00
Charlie Marsh 5b391770df
Add support for named and explicit indexes (#7481)
## Summary

This PR adds a first-class API for defining registry indexes, beyond our
existing `--index-url` and `--extra-index-url` setup.

Specifically, you now define indexes like so in a `uv.toml` or
`pyproject.toml` file:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"
```

You can also provide indexes via `--index` and `UV_INDEX`, and override
the default index with `--default-index` and `UV_DEFAULT_INDEX`.

### Index priority

Indexes are prioritized in the order in which they're defined, such that
the first-defined index has highest priority.

Indexes are also inherited from parent configuration (e.g., the
user-level `uv.toml`), but are placed after any indexes in the current
project, matching our semantics for other array-based configuration
values.

You can mix `--index` and `--default-index` with the legacy
`--index-url` and `--extra-index-url` settings; the latter two are
merely treated as unnamed `[[tool.uv.index]]` entries.

### Index pinning

If an index includes a name (which is optional), it can then be
referenced via `tool.uv.sources`:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"

[tool.uv.sources]
torch = { index = "pytorch" }
```

If an index is marked as `explicit = true`, it can _only_ be used via
such references, and will never be searched implicitly:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"
explicit = true

[tool.uv.sources]
torch = { index = "pytorch" }
```

Indexes defined outside of the current project (e.g., in the user-level
`uv.toml`) can _not_ be explicitly selected.

(As of now, we only support using a single index for a given
`tool.uv.sources` definition.)

### Default index

By default, we include PyPI as the default index. This remains true even
if the user defines a `[[tool.uv.index]]` -- PyPI is still used as a
fallback. You can mark an index as `default = true` to (1) disable the
use of PyPI, and (2) bump it to the bottom of the prioritized list, such
that it's used only if a package does not exist on a prior index:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"
default = true
```

### Name reuse

If a name is reused, the higher-priority index with that name is used,
while the lower-priority indexes are ignored entirely.

For example, given:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"

[[tool.uv.index]]
name = "pytorch"
url = "https://test.pypi.org/simple"
```

The `https://test.pypi.org/simple` index would be ignored entirely,
since it's lower-priority than `https://download.pytorch.org/whl/cu121`
but shares the same name.

Closes #171.

## Future work

- Users should be able to provide authentication for named indexes via
environment variables.
- `uv add` should automatically write `--index` entries to the
`pyproject.toml` file.
- Users should be able to provide multiple indexes for a given package,
stratified by platform:
```toml
[tool.uv.sources]
torch = [
  { index = "cpu", markers = "sys_platform == 'darwin'" },
  { index = "gpu", markers = "sys_platform != 'darwin'" },
]
```
- Users should be able to specify a proxy URL for a given index, to
avoid writing user-specific URLs to a lockfile:
```toml
[[tool.uv.index]]
name = "test"
url = "https://private.org/simple"
proxy = "http://<omitted>/pypi/simple"
```
2024-10-15 18:24:23 -04:00
samypr100 01c44af3c3
chore: unify all env vars used (#8151)
## Summary

This PR declares and documents all environment variables that are used
in one way or another in `uv`, either internally, or externally, or
transitively under a common struct.

I think over time as uv has grown there's been many environment
variables introduced. Its harder to know which ones exists, which ones
are missing, what they're used for, or where are they used across the
code. The docs only documents a handful of them, for others you'd have
to dive into the code and inspect across crates to know which crates
they're used on or where they're relevant.

This PR is a starting attempt to unify them, make it easier to discover
which ones we have, and maybe unlock future posibilities in automating
generating documentation for them.

I think we can split out into multiple structs later to better organize,
but given the high influx of PR's and possibly new environment variables
introduced/re-used, it would be hard to try to organize them all now
into their proper namespaced struct while this is all happening given
merge conflicts and/or keeping up to date.

I don't think this has any impact on performance as they all should
still be inlined, although it may affect local build times on changes to
the environment vars as more crates would likely need a rebuild. Lastly,
some of them are declared but not used in the code, for example those in
`build.rs`. I left them declared because I still think it's useful to at
least have a reference.

Did I miss any? Are their initial docs cohesive?

Note, `uv-static` is a terrible name for a new crate, thoughts? Others
considered `uv-vars`, `uv-consts`.

## Test Plan

Existing tests
2024-10-14 16:48:13 -05:00
Amos Wenger 715f28fd39
chore: Move all integration tests to a single binary (#8093)
As per
https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html

Before that, there were 91 separate integration tests binary.

(As discussed on Discord — I've done the `uv` crate, there's still a few
more commits coming before this is mergeable, and I want to see how it
performs in CI and locally).
2024-10-11 16:41:35 +02:00
konsti ad638d7fa3
Use a higher timeout for publishing (#7923) 2024-10-04 15:52:23 +02:00
Charlie Marsh 14507a1793
Add `uv-` prefix to all internal crates (#7853)
## Summary

Brings more consistency to the repo and ensures that all crates
automatically show up in `--verbose` logging.
2024-10-01 20:15:32 -04:00
Charlie Marsh 538b0f1099
Remove `serde::Serialize` implementations for rkyv-able structs (#7663)
## Summary

Random, but I noticed that we can remove a ton of serialize and
deserialize derives by using `rkyv` for the flat-index caches. (We
already use `rkyv` for these same structs in the registry cache.)
2024-09-24 13:23:47 -04:00
konsti 5da73a24cb
Rename `MetadataResolver` to `ResolutionMetadata` (#7661) 2024-09-24 16:25:19 +00:00
konsti 16a6fd2c42
Add retries to `uv publish` (#7635) 2024-09-24 16:24:44 +00:00
konsti 205bf8cabe
Implement trusted publishing (#7548)
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-09-24 16:07:20 +00:00
konsti 484717d42f
Split metadata parsing into a module (#7656) 2024-09-24 17:16:21 +02:00
konsti d9a5f5ca1c
Add `only_authenticated` option to the client (#7545) 2024-09-21 16:09:14 +02:00
Andrew Gallant 1379b530f6 uv: migrate to rkyv 0.8
Recently, rkyv 0.8 was released. Its API is a fair bit simpler now for
higher level uses (like for us in `uv`) and results in us being able to
delete a fair bit of code. This also removes our last dependency on `syn
1.0`, and thus drops that dependency.

Performance (via testing on the `transformers` example) seems to remain
about the same, which is what was expected:

```
$ hyperfine -w5 -r100 'uv lock' 'uv-ag-rkyv-update lock'
Benchmark 1: uv lock
  Time (mean ± σ):      55.6 ms ±   6.4 ms    [User: 30.4 ms, System: 35.1 ms]
  Range (min … max):    43.0 ms …  73.1 ms    100 runs

Benchmark 2: uv-ag-rkyv-update lock
  Time (mean ± σ):      56.5 ms ±   7.2 ms    [User: 30.5 ms, System: 36.3 ms]
  Range (min … max):    39.1 ms …  71.5 ms    100 runs

Summary
  uv lock ran
    1.02 ± 0.18 times faster than uv-ag-rkyv-update lock
```

Closes #7415
2024-09-18 14:49:54 -04:00
Charlie Marsh c87ce7aaf8
Run `cargo upgrade` (#7448)
Co-authored-by: konstin <konstin@mailbox.org>
2024-09-17 12:39:58 +02:00
konsti 2b3890f2b4
Extract METADATA reading into a crate (#7231)
This is preparatory work for the upload functionality, which needs to
read the METADATA file and attach its parsed contents to the POST
request: We move finding the `.dist-info` from `install-wheel-rs` and
`uv-client` to a new `uv-metadata` crate, so it can be shared with the
publish crate.

I don't properly know if its the right place since the upload code isn't
ready, but i'm PR-ing it now because it already had merge conflicts.
2024-09-10 13:31:01 +00:00
Charlie Marsh 9a7262c360
Avoid batch prefetching for un-optimized registries (#7226)
## Summary

We now track the discovered `IndexCapabilities` for each `IndexUrl`. If
we learn that an index doesn't support range requests, we avoid doing
any batch prefetching.

Closes https://github.com/astral-sh/uv/issues/7221.
2024-09-09 15:46:19 -04:00
Charlie Marsh 1c25c76be6
Make invlaid core-metadata tag non-fatal (#7046)
## Summary

One of the indexes we test against is using a non-compliant value (the
actual URL).
2024-09-04 16:44:04 -04:00
Leiser Fernández Gallo bc7b6f109e
Make headers title case for backward compatibility (#6887)
## Summary
Http headers are supposed to be case-insensitive (RFC 2616), but there
are some implementations that don't normalize them.
I noticed it while migrating to `uv`, calls to an internal registry
failed. A man in the middle server helped me to find that `pip` uses
Title-Case while `uv pip` uses lowercase.

## Test Plan

I tested `uv` with the same server and now it works fine.
2024-09-03 13:28:45 -04:00
konsti 9edf2d8132
Avoid panic with missing temporary directory (#6929)
Forward an error for missing temp directories:

```
$ env TMPDIR=.tmp uv-debug pip install httpx
  error: No such file or directory (os error 2) at path "/home/konsti/projects/uv/.tmp/.tmpgIBhhh"
```

Fixes #6878
2024-09-02 07:32:42 +00:00
Ed Morley a5f1e1c765
Fix typos in docs, error messages and comments (#6910) 2024-09-01 11:37:43 +00:00
Charlie Marsh 8fdb3a882e
Read hash from URL fragment if `--hashes` are omitted (#6731)
## Summary

Like pip, if `--hashes` are omitted but there's a valid hash in the URL
fragment, we should respect it.

Closes https://github.com/astral-sh/uv/issues/6701.
2024-08-28 00:03:01 +00:00
Charlie Marsh d86075fc1e
Add support for `--trusted-host` (#6591)
## Summary

This PR revives https://github.com/astral-sh/uv/pull/4944, which I think
was a good start towards adding `--trusted-host`. Last night, I tried to
add `--trusted-host` with a custom verifier, but we had to vendor a lot
of `reqwest` code and I eventually hit some private APIs. I'm not
confident that I can implement it correctly with that mechanism, and
since this is security, correctness is the priority.

So, instead, we now use two clients and multiplex between them.

Closes https://github.com/astral-sh/uv/issues/1339.

## Test Plan

Created self-signed certificate, and ran `python3 -m http.server --bind
127.0.0.1 4443 --directory . --certfile cert.pem --keyfile key.pem` from
the packse index directory.

Verified that `cargo run pip install
transitive-yanked-and-unyanked-dependency-a-0abad3b6 --index-url
https://127.0.0.1:8443/simple-html` failed with:

```
error: Request failed after 3 retries
  Caused by: error sending request for url (https://127.0.0.1:8443/simple-html/transitive-yanked-and-unyanked-dependency-a-0abad3b6/)
  Caused by: client error (Connect)
  Caused by: invalid peer certificate: Other(OtherError(CaUsedAsEndEntity))
```

Verified that `cargo run pip install
transitive-yanked-and-unyanked-dependency-a-0abad3b6 --index-url
'https://127.0.0.1:8443/simple-html' --trusted-host '127.0.0.1:8443'`
failed with the expected error (invalid resolution) and made valid
requests.

Verified that `cargo run pip install
transitive-yanked-and-unyanked-dependency-a-0abad3b6 --index-url
'https://127.0.0.1:8443/simple-html' --trusted-host '127.0.0.2' -n` also
failed.
2024-08-27 09:36:50 -04:00
Charlie Marsh 1eb97c91fd
Remove `FileLocation::Path` variant (#6577)
## Summary

This is redundant now that we support `file://` URLs.
2024-08-24 07:52:43 -04:00
Charlie Marsh c743705dfb
Revert "Cache downloaded wheel when range requests aren't supported" (#6470)
## Summary

This reverts commit 7d92915f3d.

I thought this would be a net performance improvement, but we've now had
multiple reports that this made locking _extremely_ slow. I also tested
this today with a very large codebase against a registry that does not
support range requests, and the number of downloads was sort of wild to
watch. Reverting the reduced resolution time by over 50%.

Closes #6104.
2024-08-22 19:54:42 -04:00
Charlie Marsh 42498c8c63
Ignore workspace discovery errors with `--no-workspace` (#6328)
## Summary

It's useful to try to discover the workspace, so we can warn, but it's
not good to fail.

Closes https://github.com/astral-sh/uv/issues/6320.
2024-08-21 14:30:01 +00:00
Andrew Gallant 33480d61eb switch to jiff from chrono (#6205)
This PR migrates uv's use of `chrono` to `jiff`.

I did most of this work a while back as one of my tests to ensure Jiff
could actually be used in a real world project. I decided to revive
this because I noticed that `reqwest-retry` dropped its Chrono
dependency,
which is I believe the only other thing requiring Chrono in uv.
(Although, we use a fork of `reqwest-middleware` at present, and that
hasn't been updated to latest upstream yet. I wasn't quite sure of the
process we have for that.)

In course of doing this, I actually made two changes to uv:

First is that the lock file now writes an RFC 3339 timestamp for
`exclude-newer`. Previously, we were using Chrono's `Display`
implementation for this which is a non-standard but "human readable"
format. I think the right thing to do here is an RFC 3339 timestamp.

Second is that, in addition to an RFC 3339 timestamp, `--exclude-newer`
used to accept a "UTC date." But this PR changes it to a "local date."
That is, a date in the user's system configured time zone. I think
this makes more sense than a UTC date, but one alternative is to drop
support for a date and just rely on an RFC 3339 timestamp. The main
motivation here is that automatically assuming UTC is often somewhat
confusing, since just writing an unqualified date like `2024-08-19` is
often assumed to be interpreted relative to the writer's "local" time.
2024-08-20 11:31:46 -05:00
Charlie Marsh 3395d24959
Allow user to constrain supported lock environments (#6210)
## Summary

The strategy here is: if the user provides supported environments, we
use those as the initial forks when resolving. As a result, we never add
or explore branches that are disjoint with the supported environments.
(If the supported environments change, we ignore the lockfile entirely,
so we don't have to worry about any interactions between supported
environments and the preference forks.)

Closes https://github.com/astral-sh/uv/issues/6184.
2024-08-20 13:28:04 +00:00
konsti fcbee9ce25
Support relative path wheels (#5969)
Surprisingly, this is a lockfile schema change: We can't store relative
paths in urls, so we have to store a `filename` entry instead of the
whole url.

Fixes #4355
2024-08-09 21:57:16 +00:00
Charlie Marsh 21408c1f35
Enforce extension validity at parse time (#5888)
## Summary

This PR adds a `DistExtension` field to some of our distribution types,
which requires that we validate that the file type is known and
supported when parsing (rather than when attempting to unzip). It
removes a bunch of extension parsing from the code too, in favor of
doing it once upfront.

Closes https://github.com/astral-sh/uv/issues/5858.
2024-08-08 21:39:47 -04:00
Andrew Gallant 5b8ed92f95 uv-client: switch heuristic freshness lifetime to hard-coded value
The comment in the code explains the bulk of this:

```rust
// We previously computed this heuristic freshness lifetime by
// looking at the difference between the last modified header and
// the response's date header. We then asserted that the cached
// response ought to be "fresh" for 10% of that interval.
//
// It turns out that this can result in very long freshness
// lifetimes[1] that lead to uv caching too aggressively.
//
// Since PyPI sets a max-age of 600 seconds and since we're
// principally just interacting with Python package indices here,
// we just assume a freshness lifetime equal to what PyPI has.
//
// Note though that a better solution here is for the index to
// support proper HTTP caching headers (ideally Cache-Control, but
// Expires also works too, as above).
```

We also remove the `heuristic_percent` field on `CacheConfig`. Since
that's actually part of the cache itself, we bump the simple cache
version.

Finally, we add some more `trace!` calls that should hopefully make
diagnosing issues related to the freshness lifetime a bit easier in the
future.

Fixes #5351
2024-07-31 08:12:11 -07:00
konsti 0877f76aae
Retry on incomplete body (#5555)
This is an attempt to add
https://github.com/astral-sh/uv/issues/3514#issuecomment-2253562096 to
retrying.

Relevant hyper code:
*
15cd6fa1fc/src/proto/h1/decode.rs (L683)
*
15cd6fa1fc/src/proto/h1/decode.rs (L161-L164)
2024-07-29 15:53:23 +02:00
Charlie Marsh 24859bd3ee
Upgrade to Rust 1.80.0 (#5472) 2024-07-27 01:49:47 +00:00
Charlie Marsh 561625ed8c
Use hasher to compute resolution hash (#5495)
## Summary

Addressing one TODO. This should be more efficient.
2024-07-26 23:24:09 +00:00
Zanie Blue 3e067766de
Stylize `Requires-Python` consistently (#5304) 2024-07-23 18:05:21 +00:00
Charlie Marsh 097acb628d
Remove Simple API cache files for alternative indexes in `cache clean` (#5353)
## Summary

The `simple-v9` directory was missing the `index` segment. See before:


![Screenshot 2024-07-23 at 1 29
18 PM](https://github.com/user-attachments/assets/3af9ccbf-ba45-4910-ad3b-4f52806dc8c9)

And after:

![Screenshot 2024-07-23 at 1 29
38 PM](https://github.com/user-attachments/assets/15535534-3304-4209-93e8-7f5e572929f0)

Every other bucket has this `index` segment for non-PyPI indexes, e.g.:

![Screenshot 2024-07-23 at 1 29
24 PM](https://github.com/user-attachments/assets/7354c9ad-7757-4a5f-a7b8-ff987a100e39)

Closes https://github.com/astral-sh/uv/issues/5352.
2024-07-23 13:42:51 -04:00
Zack Elia f371195536
Allow symlinks with `--find-links` (#5323)
## Summary

In my setup, I have a directory of wheels symlinked from different
directories. I can point `--find-links` at it with `pip` and it works
but not `uv`.

Currently, `uv` checks if a candidate file `is_file` which is for
regular files. By also checking `is_symlink` I was able to install a
symlinked wheel. I'm not *exactly* sure where, but some other place is
eventually resolving the absolute path of the wheel. (`uv`? The OS?)

## Test Plan

Manually tested - I didn't see any tests for `FlatIndexClient` in the
`uv-client` crate.

```
mkdir /tmp/a /tmp/b                               # Create a directory of wheels (/tmp/a) and a directory of symlinked wheels (/tmp/b)
cp test-0.0.1-py3-none-any.whl /tmp/a             # Add a wheel to the directory of wheels
ln -s /tmp/a/test-0.0.1-py3-none-any.whl /tmp/b/  # Create a symlink to that wheel
uv pip install test --find-links /tmp/b           # Install pointing at the symlinked wheels directory
```
2024-07-23 02:53:39 +00:00
Charlie Marsh 5c3d55afa8
Remove unused error variant (#5266) 2024-07-21 23:38:45 +00:00
Charlie Marsh ed9b820815
Remove trailing period from user-facing messages (#5218)
## Summary

Per #5209, we only show periods in messages when the message itself
spans more than a single sentence.
2024-07-19 10:43:49 -04:00
Charlie Marsh 2ff3b380b1
Cache downloaded wheel when range requests aren't supported (#5089)
## Summary

When range requests aren't supported, we fall back to streaming the
wheel, stopping as soon as we hit a `METADATA` file. This is a small
optimization, but the downside is that we don't get to cache the
resulting wheel...

We don't know whether `METADATA` will be at the beginning or end of the
wheel, but it _seems_ like a better tradeoff to download and cache the
entire wheel?

Closes: https://github.com/astral-sh/uv/issues/5088.

Sort of a revert of: https://github.com/astral-sh/uv/pull/1792.
2024-07-16 09:21:47 -04:00
Zanie Blue 9997dc0870
There are no rage requests here (#5037) 2024-07-13 15:35:51 +00:00