Commit graph

4903 commits

Author SHA1 Message Date
Charlie Marsh
7585250107
Report yanked distributions in --dry-run (#3740)
## Summary

Closes #3703.
2024-05-22 16:37:11 +00:00
Zanie Blue
5fe891082d
Discover and prefer the parent interpreter when invoked with python -m uv (#3736)
Closes #2222
Closes https://github.com/astral-sh/uv/issues/2058
Replaces https://github.com/astral-sh/uv/pull/2338
See also https://github.com/astral-sh/uv/issues/2649

We use an environment variable (`UV_INTERNAL__PARENT_INTERPRETER`) to
track the invoking interpreter when `python -m uv` is used. The parent
interpreter is preferred over all other sources (though it will be
skipped if it does not meet a `--python` request or if `--system` is
used and it belongs to a virtual environment). We warn if `--system` is
not provided and this interpreter would mutate system packages, but
allow it.
2024-05-22 11:34:24 -05:00
Charlie Marsh
b92321bd2d
Allow --constraint files in pip sync (#3741)
## Summary

Trivial now that this follows the same strategy and internals as `pip
install`.

Closes https://github.com/astral-sh/uv/issues/3438.
2024-05-22 16:30:54 +00:00
Zanie Blue
7afc3f6eb0
Filter discovered Python interpreters by system preference (#3739)
Previously, we enforced `SystemPython` outside of the interpreter
discovery exclusively with source selection. Now, we perform additional
filtering of interpreters depending on if they are a virtual
environment. This should not change any existing behavior, but will make
it much easier to have consistent behavior in ambiguous cases like
https://github.com/astral-sh/uv/pull/3736#discussion_r1610072262 where a
source could provide either a system interpreter or virtual environment
interpreter.
2024-05-22 11:22:09 -05:00
Charlie Marsh
0313e7d78b
Use common routines for pip install and pip sync (#3737)
## Summary

This PR takes the functions used in `pip install`, moves them into a
common module, and then replaces all the `pip sync` logic with calls
into those functions. The net effect is that `pip install` and `pip
sync` share far more code and demonstrate much more consistent behavior.

Closes https://github.com/astral-sh/uv/issues/3555.
2024-05-22 12:15:17 -04:00
Zanie Blue
b8ef436c42
Do not display "py launcher" source in error messages on Unix (#3738) 2024-05-22 15:22:15 +00:00
Charlie Marsh
2a01cbed65
Document --only-binary compatibility (#3735)
## Summary

Closes https://github.com/astral-sh/uv/issues/2620.
2024-05-22 10:46:28 -04:00
Charlie Marsh
ac05a13e81
Add --prefix link to compatibility guide (#3734) 2024-05-22 13:45:51 +00:00
Charlie Marsh
e398444f2f
Track editable requirements in lockfile (#3725)
## Summary

This PR adds editables using a new source type (`editable+...`), and
then extracts the editables from the lockfile in `uv sync`.

Closes https://github.com/astral-sh/uv/issues/3695.
2024-05-22 09:06:18 -04:00
Charlie Marsh
472ab144d5
Remove maturin_editable test (#3718)
## Summary

I personally think this isn't worth continuing to maintain.
2024-05-22 11:10:04 +02:00
Charlie Marsh
d912c37539
Add instructions for building and updating uv-trampolines (#3731) 2024-05-21 22:49:14 -04:00
Ofek Lev
82820d0f4c
Allow relative Python executable paths in Windows trampoline (#3717)
## Summary

This is a prerequisite for https://github.com/astral-sh/uv/issues/3669

## Test Plan

Download one of the standalone distributions on Windows then use its
Python to run the following script and then run the scripts it creates
(only pip):

```python
from __future__ import annotations

import sys
import sysconfig
from contextlib import closing
from importlib.metadata import entry_points
from io import BytesIO
from os.path import relpath
from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo

# Change this line to your real path
LAUNCHERS_DIR = Path('C:\\Users\\ofek\\Desktop\\code\\uv\\crates\\uv-trampoline\\target\\x86_64-pc-windows-msvc\\release')
SCRIPT_TEMPLATE = """\
#!{executable}
# -*- coding: utf-8 -*-
import re
import sys
from {module} import {import_name}
if __name__ == "__main__":
    sys.argv[0] = re.sub(r"(-script\\.pyw|\\.exe)?$", "", sys.argv[0])
    sys.exit({function}())
"""


def select_entry_points(ep, group):
    return ep.select(group=group) if sys.version_info[:2] >= (3, 10) else ep.get(group, [])


def main():
    interpreters_dir = Path(sys.executable).parent
    scripts_dir = Path(sysconfig.get_path('scripts'))

    ep = entry_points()
    for group, interpreter_name, launcher_name in (
        ('console_scripts', 'python.exe', 'uv-trampoline-console.exe'),
        ('gui_scripts', 'pythonw.exe', 'uv-trampoline-gui.exe'),
    ):
        interpreter = interpreters_dir / interpreter_name
        relative_interpreter_path = relpath(interpreter, scripts_dir)
        launcher_data = (LAUNCHERS_DIR / launcher_name).read_bytes()

        for script in select_entry_points(ep, group):
            # https://github.com/astral-sh/uv/tree/main/crates/uv-trampoline#how-do-you-use-it
            with closing(BytesIO()) as buf:
                # Launcher
                buf.write(launcher_data)

                # Zipped script
                with TemporaryDirectory() as td:
                    zip_path = Path(td) / 'script.zip'
                    with ZipFile(zip_path, 'w') as zf:
                        # Ensure reproducibility
                        zip_info = ZipInfo('__main__.py', (2020, 2, 2, 0, 0, 0))
                        zip_info.external_attr = (0o644 & 0xFFFF) << 16

                        module, _, attrs = script.value.partition(':')
                        contents = SCRIPT_TEMPLATE.format(
                            executable=relative_interpreter_path,
                            module=module,
                            import_name=attrs.split('.')[0],
                            function=attrs
                        )
                        zf.writestr(zip_info, contents, compress_type=ZIP_DEFLATED)

                    buf.write(zip_path.read_bytes())

                # Interpreter path
                interpreter_path = relative_interpreter_path.encode('utf-8')
                buf.write(interpreter_path)

                # Interpreter path length
                interpreter_path_length = len(interpreter_path).to_bytes(4, 'little')
                buf.write(interpreter_path_length)

                # Magic number
                buf.write(b'UVUV')

                script_data = buf.getvalue()

            script_path = scripts_dir / f'{script.name}.exe'
            script_path.write_bytes(script_data)


if __name__ == '__main__':
    main()
```
2024-05-21 21:53:15 -04:00
Zanie Blue
becdc64d3e
Do not discover virtual environment interpreters in uv venv --python ... (#3728)
Otherwise `uv venv --python 3.12` can prefer `.venv/bin/python` over the
system Python (which is always used if you don't provide a `--python`
flag). I would find this confusing as a user.
2024-05-21 20:00:21 -05:00
Charlie Marsh
e71ce53983
Allow --config-file to be passed before or after command name (#3730) 2024-05-22 00:12:10 +00:00
Charlie Marsh
d33577fc16
Make --offline a global argument (#3729) 2024-05-22 00:09:05 +00:00
Charlie Marsh
285adaed64
Remove some dependencies on EditableRequirement (#3727)
## Summary

Use `LocalEditable` instead throughout the `ResolvedEditable` pipeline.
2024-05-21 23:36:53 +00:00
Zanie Blue
1379fb7dcd
Add support for requesting pypy interpreters by implementation name (#3706)
Updates our executable name searches to support implementation names
i.e. `cpython` and `pypy` and adds support for PyPy.

We might want to _not_ support searching for `cpython` because that's
non-standard?
2024-05-21 16:48:43 -05:00
Zanie Blue
84afca2696
Add offline support to uv tool run and uv run (#3676)
Adds `--offline` support to `uv tool run` and `uv run` because I needed
it on the airplane today.

I think we should move `--offline` to the global settings like
`--native-tls`.
2024-05-21 15:58:15 -05:00
Charlie Marsh
e0b639828d
Revert "Support editables in uv sync (#3692)" (#3696) (#3722)
## Summary

This is just a re-apply of #3696, which @konstin accidentally reverted
in #3585.

Co-authored-by: konsti <konstin@mailbox.org>
2024-05-21 16:41:15 -04:00
Zanie Blue
92c70134d1
Fix uv tool run interpreter lookup (#3721) 2024-05-21 16:33:39 -04:00
Charlie Marsh
558f628ef1
Propagate URL errors in verbatim parsing (#3720)
## Summary

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

## Test Plan

```
❯ echo "/../test" | cargo run pip compile -
error: Couldn't parse requirement in `-` at position 0
  Caused by: path could not be normalized: /../test
/../test
^^^^^^^^

❯ echo "-e /../test" | cargo run pip compile -
error: Invalid URL in `-`: `/../test`
  Caused by: path could not be normalized: /../test
  Caused by: cannot normalize a relative path beyond the base directory
```
2024-05-21 19:58:59 +00:00
Zanie Blue
19df1a4372
Rename all instances of Cpython to CPython (#3702) 2024-05-21 14:52:31 -05:00
Zanie Blue
d313d9b1fa
Add initial implementation of uv tool run (#3657)
This is mostly a shorter version of `uv run` that infers a requirement
name from the command. The main goal here is to do the smallest amount
of work necessary to get #3560 started.

Closes #3613 

e.g.
```shell
$ uv tool run -- ruff check
warning: `uv tool run` is experimental and may change without warning.
Resolved 1 package in 34ms
Installed 1 package in 2ms
 + ruff==0.4.4
error: Failed to parse example.py:1:5: Expected an expression
example.py:1:5: E999 SyntaxError: Expected an expression
Found 1 error.
```
2024-05-21 19:51:30 +00:00
Zanie Blue
d540d0f28b
Rewrite Python interpreter discovery (#3266)
Updates our Python interpreter discovery to conform to the rules
described in #2386, please see that issue for a full description of the
behavior. Briefly, we now will search for interpreters that satisfy a
requested version without stopping at the first Python executable.
Additionally, if retrieving information about an interpreter fails we
will continue to search for a working interpreter. We also add the
plumbing necessary to request Python implementations other than CPython,
though we do not add support for other implementations at this time.

A major internal goal of this work is to prepare for user-facing managed
toolchains i.e. fetching a requested version during `uv run`. These APIs
are not introduced, but there is some managed toolchain handling as
required for our test suite.

Some noteworthy implementation changes:

- The `uv_interpreter::find_python` module has been removed in favor of
a `uv_interpreter::discovery` module.
- There are new types to help structure interpreter requests and track
sources
- Executable discovery is implemented as a big lazy iterator and is a
central authority for source precedence
- `uv_interpreter::Error` variants were split into scoped types in each
module
- There's much more unit test coverage, but not for Windows yet

Remaining work:

- [x] Write new test cases
- [x] Determine correct behavior around executables in the current
directory
- _Future_: Combine `PythonVersion` and `VersionRequest`
- _Future_: Consider splitting `ManagedToolchain` into local and remote
variants
- _Future_: Add Windows unit test coverage
- _Future_: Explore behavior around implementation precedence (i.e.
CPython over PyPy)

Refactors split into:

- #3329 
- #3330 
- #3331
- #3332

Closes #2386
2024-05-21 14:37:23 -05:00
Zanie Blue
c14a7dbef3
Improve display of root package in range errors (#3711)
Instead of saying 

> we can conclude that you require==0a0.dev0 and
pandas-stubs==2.0.3.230814 are incompatible.

we'll say

> we can conclude that your requirements and pandas-stubs==2.0.3.230814
are incompatible.

Closes #3710 

I'm not sure how to get unit test coverage for this, might look into
that. Ideally we'd skip this branch entirely?
2024-05-21 19:28:23 +00:00
Zanie Blue
dfd6ccf0f9
Move maturin test coverage into CI (#3714)
This test can take over 60s to run, which is too much for a unit test.
We'll run it in a separate CI job to retain coverage.
2024-05-21 19:17:48 +00:00
Charlie Marsh
cf997080b0
Rename DistInfoMetadata to CoreMetadata (#3699)
## Summary

This reflects the change codified in PEP 714.
2024-05-21 18:26:59 +00:00
Charlie Marsh
fee344db6f
Add PEP 714 support for HTML API client (#3697)
## Summary

If `data-core-metadata` is set, we need to respect that over
`data-dist-info-metadata` in the HTML client.

See: https://github.com/astral-sh/uv/issues/3689
2024-05-21 18:05:40 +00:00
konsti
e6a5da7424
Fix clippy on main by boxing large error variant (#3707)
I don't really understand why this only happens on windows clippy and
not on linux too, but as usual, boxing the error variant fixes it.

Fixup for #3585
2024-05-21 17:55:43 +00:00
konsti
2ffd453003
Discover workspaces without using them in resolution (#3585)
Add minimal support for workspace discovery, only used for determining
paths in the bluejay commands.

We can now discover the workspace structure, namely that the
`pyproject.toml` of a package belongs to a workspace `pyproject.toml`
with members and exclusion. The globbing logic is inspired by cargo. We
don't resolve `workspace = true` metadata declarations yet.
2024-05-21 17:17:26 +00:00
Charlie Marsh
5205165d42
Add PEP 714 support for JSON API client (#3698)
## Summary

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

## Test Plan

Manually verified we pick up `core-metadata` from PyPI if I remove the
aliases.
2024-05-21 15:52:37 +00:00
konsti
95af1db0bb
Let RequirementSource::Path.editable be bool, not Option<bool> (#3693)
Small refactoring of the internal representation. This does not change
`tool.uv.sources`.
2024-05-21 14:34:43 +00:00
konsti
f396c6c33e
Revert "Support editables in uv sync (#3692)" (#3696)
This reverts commit #3692 until we get the editables from the lockfile.
2024-05-21 14:11:36 +00:00
konsti
647f70505e
Abort tests running for more than 60s to catch deadlocks (#3694)
We observed recent deadlocks (e.g.
2522386625)
causing CI to run until the default github actions timeout. To prevent
this, we add a 60s timeout in nextest. 60s should be enough both on CI
and on developers' machines.
2024-05-21 13:19:57 +00:00
konsti
76418f5bdf
Arc-wrap PubGrubPackage for cheap cloning in pubgrub (#3688)
Pubgrub stores incompatibilities as (package name, version range)
tuples, meaning it needs to clone the package name for each
incompatibility, and each non-borrowed operation on incompatibilities.
https://github.com/astral-sh/uv/pull/3673 made me realize that
`PubGrubPackage` has gotten large (expensive to copy), so like `Version`
and other structs, i've added an `Arc` wrapper around it.

It's a pity clippy forbids `.deref()`, it's less opaque than `&**` and
has IDE support (clicking on `.deref()` jumps to the right impl).

## Benchmarks

It looks like this matters most for complex resolutions which, i assume
because they carry larger `PubGrubPackageInner::Package` and
`PubGrubPackageInner::Extra` types.

```bash
hyperfine --warmup 5 "./uv-main pip compile -q ./scripts/requirements/jupyter.in" "./uv-branch pip compile -q ./scripts/requirements/jupyter.in"
hyperfine --warmup 5 "./uv-main pip compile -q ./scripts/requirements/airflow.in" "./uv-branch pip compile -q ./scripts/requirements/airflow.in"
hyperfine --warmup 5 "./uv-main pip compile -q ./scripts/requirements/boto3.in" "./uv-branch pip compile -q ./scripts/requirements/boto3.in"
```

```
Benchmark 1: ./uv-main pip compile -q ./scripts/requirements/jupyter.in
  Time (mean ± σ):      18.2 ms ±   1.6 ms    [User: 14.4 ms, System: 26.0 ms]
  Range (min … max):    15.8 ms …  22.5 ms    181 runs

Benchmark 2: ./uv-branch pip compile -q ./scripts/requirements/jupyter.in
  Time (mean ± σ):      17.8 ms ±   1.4 ms    [User: 14.4 ms, System: 25.3 ms]
  Range (min … max):    15.4 ms …  23.1 ms    159 runs

Summary
  ./uv-branch pip compile -q ./scripts/requirements/jupyter.in ran
    1.02 ± 0.12 times faster than ./uv-main pip compile -q ./scripts/requirements/jupyter.in
```

```
Benchmark 1: ./uv-main pip compile -q ./scripts/requirements/airflow.in
  Time (mean ± σ):     153.7 ms ±   3.5 ms    [User: 165.2 ms, System: 157.6 ms]
  Range (min … max):   150.4 ms … 163.0 ms    19 runs

Benchmark 2: ./uv-branch pip compile -q ./scripts/requirements/airflow.in
  Time (mean ± σ):     123.9 ms ±   4.6 ms    [User: 152.4 ms, System: 133.8 ms]
  Range (min … max):   118.4 ms … 138.1 ms    24 runs

Summary
  ./uv-branch pip compile -q ./scripts/requirements/airflow.in ran
    1.24 ± 0.05 times faster than ./uv-main pip compile -q ./scripts/requirements/airflow.in
```

```
Benchmark 1: ./uv-main pip compile -q ./scripts/requirements/boto3.in
  Time (mean ± σ):     327.0 ms ±   3.8 ms    [User: 344.5 ms, System: 71.6 ms]
  Range (min … max):   322.7 ms … 334.6 ms    10 runs

Benchmark 2: ./uv-branch pip compile -q ./scripts/requirements/boto3.in
  Time (mean ± σ):     311.2 ms ±   3.1 ms    [User: 339.3 ms, System: 63.1 ms]
  Range (min … max):   307.8 ms … 317.0 ms    10 runs

Summary
  ./uv-branch pip compile -q ./scripts/requirements/boto3.in ran
    1.05 ± 0.02 times faster than ./uv-main pip compile -q ./scripts/requirements/boto3.in
```

<!--
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?
-->
2024-05-21 13:49:35 +02:00
konsti
fbae55019e
Support editables in uv sync (#3692)
This is bare-bones support for editables in `uv sync` as basis for
workspace support, notably without lockfile integration. It leverages
the existing `ResolvedEditables` infrastructure.
2024-05-21 11:30:15 +00:00
konsti
d326e1f5e9
Better error message for uv run failures (#3691)
Attach path context to `uv run` failures since those function calls are
not covered by `fs_err`.
2024-05-21 11:24:18 +00:00
konsti
2c4088a518
Improve DirWithoutEntrypoint error message (#3690)
Ran into this and couldn't tell what the problem was without the path
attached.
2024-05-21 11:21:20 +00:00
Henry Schreiner
906f653062
ci: drop native manylinux wheel for dual-tagged one (#3685)
<!--
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

<!-- What's the purpose of the change? What does it do, and why? -->

Followup to #3624. Drops the native manylinux wheel in favor of the
statically linked musl one with a manylinux2014 tag.

<!-- How was it tested? -->

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-05-21 11:55:08 +02:00
Zanie Blue
acde048151
Add notes for testing on windows (#3658) 2024-05-21 08:40:22 +00:00
Charlie Marsh
49f0e84f3d
Write relative paths with unnamed requirement syntax (#3682)
## Summary

This PR falls back to writing an unnamed requirement if it appears to be
a relative URL. pip is way more flexible when providing an unnamed
requirement than when providing a PEP 508 requirement. For example,
_only_ this works:

```
black @ file:///Users/crmarsh/workspace/uv/scripts/packages/black_editable
```

Any other form will fail.

Meanwhile, _all_ of these work:

```
file:///Users/crmarsh/workspace/uv/scripts/packages/black_editable
scripts/packages/black_editable
./scripts/packages/black_editable
file:./scripts/packages/black_editable
file:scripts/packages/black_editable
```

Closes https://github.com/astral-sh/uv/issues/3180.
2024-05-20 21:22:06 -04:00
Charlie Marsh
0362918196
Evaluate arbitrary markers to false (#3681)
## Summary

See: https://github.com/astral-sh/uv/pull/3679#issuecomment-2121387428.

Closes: https://github.com/astral-sh/uv/issues/3675 (although I think we
have another improvement to make there -- will file separately).
2024-05-21 01:01:11 +00:00
Andrew Gallant
776a7e47f3 uv-resolver: add Option<MarkerTree> to PubGrubPackage
This just adds the field to the type and always sets it to `None`. There
are semantic changes in this commit.

Closes #3359
2024-05-20 19:56:24 -04:00
Andrew Gallant
d0435ef20a pep508: add PartialOrd and Ord implementations to MarkerTree
Since we're adding a `Option<MarkerTree>` to `PubGrubPackage`, and since
we just make `PubGrubPackage` implement `Ord`, it follows that we want
`MarkerTree` to also implement `Ord`.
2024-05-20 19:56:24 -04:00
Andrew Gallant
1ed3555bf0 uv-resolver: sort in format_terms
This makes use of the newly added `Ord` impl on `PubGrubPackage` to make
the output of `format_terms` independent of hashmap iteration order.

This was already collecting the terms into an intermediate `Vec`, so
sorting probably isn't going to add any significant overhead here.
(Plus, this is only running when formatting an error message after a
solution could not be found, so an extra sort doesn't seem like a big
deal here.)

Note that some tests are updated in this commit as a result of this
change. As far as I can tell, the semantic meaning of the output remains
the same. But the order of the listed packages does not.

Specific thing motivating this change is, in a subsequent, I added
`Option<MarkerTree>` to `PubGrubPackage::Package`, and this caused
similar changes in test output. So I backtracked and isolated this
change from the addition of `Option<MarkerTree>`.
2024-05-20 19:56:24 -04:00
Andrew Gallant
976bc9ba0e uv-resolver: make PubGrubPackage orderable
It turns out that we use PubGrubPackage as the key in hashmaps in a fair
few places. And when we iterate over hashmaps, the order is unspecified.
This can in turn result in changes in output as a result of changes in
the PubGrubPackage definition, purely as a function of its changing
hash. This is confusing as there should be no semantic difference.

Thus, this is a precursor to introducing some more determinism to places
I found in the error reporting whose output depending on hashmap
iteration order.
2024-05-20 19:56:24 -04:00
Andrew Gallant
9f109f243c uv-resolver: remove 'derive(Derivative)' from PubGrubPackage
It looks like the last vestiges of `Derivative` were removed in commit
7eaed07f6c, but the then rendered
superfluous `derive(Derivative)` wasn't removed.
2024-05-20 19:56:24 -04:00
Andrew Gallant
eac8221718 uv-resolver: use named fields for some PubGrubPackage variants
I'm planning to add another field here (markers), which puts a lot of
stress on the positional approach. So let's just switch over to named
fields.
2024-05-20 19:56:24 -04:00
Charlie Marsh
44fe0f6749
Add rustdoc links to marker.rs documentation (#3680) 2024-05-20 23:29:15 +00:00
Charlie Marsh
a33a05e2d9
Bump version to v0.1.45 (#3674) 2024-05-20 16:34:05 -04:00