Commit Graph

707 Commits

Author SHA1 Message Date
Zanie 43910a8e9a DEMO: Include the installed version in the message 2024-01-21 19:44:17 -06:00
Zanie 044c354647 If we do not use `take(2)`... 2024-01-21 17:21:23 -06:00
Zanie 83bda6621c Use owned versions in `PythonRequirement` 2024-01-21 10:18:34 -06:00
Zanie 334dc1ea08 Fix typo 2024-01-19 15:30:56 -06:00
Zanie 4a5a1a5916 Lint 2024-01-19 15:27:57 -06:00
Zanie 066b800def Drop extra version display (was from debugging) 2024-01-19 15:19:37 -06:00
Zanie 35b2b8874d Merge branch 'main' into zb/python
# Conflicts:
#	crates/puffin/tests/pip_compile.rs
#	crates/puffin/tests/pip_install_scenarios.rs
2024-01-19 15:06:51 -06:00
Charlie Marsh d55e34c310
Make editable URL parsing more robust (#1018)
This just generalizes the parsing to handle arbitrary schemes instead of
encoding a fixed list.
2024-01-19 16:01:33 -05:00
Zanie f071a03e9f Do a simpler comparison instead of extending `Version` 2024-01-19 15:01:11 -06:00
Zanie eeadecdede Attach Python requirements to no solution errors to improve messaging 2024-01-19 14:52:39 -06:00
Charlie Marsh 72924935f8
Upgrade cargo-dist (#1016) 2024-01-19 20:19:02 +00:00
Charlie Marsh c66395977d
Rename `pep440-rs` to `Readme.md` (#1014)
This is due to a bug in Maturin
(https://github.com/PyO3/maturin/pull/1915), so I'll just fix our setup
to work with existing versions.

Closes https://github.com/astral-sh/puffin/issues/991.
2024-01-19 15:16:12 -05:00
Charlie Marsh 7b365195cb
Add support for ARM Linux builds in release (#1012)
Closes #992.
2024-01-19 15:13:07 -05:00
Zanie a0c116444d Use current Python version in `requires-python` incompatibility errors
# Conflicts:
#	crates/puffin/tests/pip_compile.rs
#	crates/puffin/tests/pip_install_scenarios.rs
2024-01-19 11:35:00 -06:00
Zanie Blue 33b35f7020
Add support for disabling installation from pre-built wheels (#956)
Adds support for disabling installation from pre-built wheels i.e. the
package must be built from source locally.
We will still always use pre-built wheels for metadata during
resolution.

Available via `--no-binary` and `--no-binary-package <name>` flags in
`pip install` and `pip sync`. There is no flag for `pip compile` since
no installation happens there.

```
--no-binary

    Don't install pre-built wheels.
    
    When enabled, all installed packages will be installed from a source distribution. 
    The resolver will still use pre-built wheels for metadata.


--no-binary-package <NO_BINARY_PACKAGE>

    Don't install pre-built wheels for a specific package.
    
    When enabled, the specified packages will be installed from a source distribution. 
    The resolver will still use pre-built wheels for metadata.
```

When packages are already installed, the `--no-binary` flag will have no
affect without the `--reinstall` flag. In the future, I'd like to change
this by tracking if a local distribution is from a pre-built wheel or a
locally-built wheel. However, this is significantly more complex and
different than `pip`'s behavior so deferring for now.

For reference, `pip`'s flag works as follows:

```
--no-binary <format_control>

    Do not use binary packages. Can be supplied multiple times, and each time adds to the
    existing value. Accepts either ":all:" to disable all binary packages, ":none:" to empty the
    set (notice the colons), or one or more package names with commas between them (no colons).
    Note that some packages are tricky to compile and may fail to install when this option is
    used on them.
```

Note we are not matching the exact `pip` interface here because it seems
complicated to use. I think we may want to consider adjusting our
interface for this behavior since we're not entirely compatible anyway
e.g. I think `--force-build` and `--force-build-package` are clearer
names. We could also consider matching the `pip` interface or only
allowing `--no-binary <package>` for compatibility. We can of course do
whatever we want in our _own_ install interfaces later.

Additionally, we may want to further consider the semantics of
`--no-binary`. For example, if I run `pip install pydantic --no-binary`
I expect _just_ Pydantic to be installed without binaries but by default
we will build all of Pydantic's dependencies too.

This work was prompted by #895, as it is much easier to measure
performance gains from building source distributions if we have a flag
to ensure we actually build source distributions. Additionally, this is
a flag I have used frequently in production to debug packages that ship
Cythonized wheels.
2024-01-19 11:24:27 -06:00
Zanie Blue 8b49d900bd
Refer to the user instead of "root" when mentioning direct dependencies (#982)
Closes https://github.com/astral-sh/puffin/issues/857
2024-01-19 11:17:42 -06:00
Zanie Blue ae7a2cddc2
Avoid showing negations of ranges in error messages (#981)
Closes https://github.com/astral-sh/puffin/issues/980
2024-01-19 11:07:14 -06:00
Zanie Blue 02ed195982
Improve simple no version messages using complement of range (#979)
Improves some of the "no versions of <package> are available" messages
by showing the complement or inversion of the package.

Does not address cases like

```
Because there are no versions of crow that satisfy any of:
    crow>1.0.0,<2.0.0a5
    crow>2.0.0a7,<2.0.0b1
    crow>2.0.0b1,<2.0.0b5
...
```

which are a bit more complicated; I'll focus on those cases in a
follow-up.
2024-01-19 16:48:20 +00:00
Zanie Blue 7bb4fda8af
Say "depend on" instead of "depends on" when proper in error messages (#968)
I would like to spend some additional time working on the package range
display abstractions, but maybe that is best done _after_ I've done a
good bit of fiddling with the error messages.

Addresses
https://github.com/astral-sh/puffin/pull/868#discussion_r1447593081
2024-01-19 16:08:17 +00:00
Zanie Blue 5fe3444e5a
Use more realistic names in scenario snapshots (#978)
This is helpful to make the error messages more realistic and the names
are indisputably cuter.
2024-01-19 10:01:34 -06:00
Charlie Marsh 5adb08a304
Allow relative paths and environment variables in all editable representations (#1000)
## Summary

I don't know if this is actually a good change, but it tries to make the
editable install experience more consistent. Specifically, we now
support...

```
# Use a relative path with a `file://` prefix.
# Prior to this PR, we supported `file:../foo`, but not `file://../foo`, which felt inconsistent.
-e file://../foo

# Use environment variables with paths, not just URLs.
# Prior to this PR, we supported `file://${PROJECT_ROOT}/../foo`, but not the below.
-e ${PROJECT_ROOT}/../foo
```

Importantly, `-e file://../foo` is actually not supported by pip... `-e
file:../foo` _is_ supported though. We support both, as of this PR. Open
to feedback.
2024-01-19 09:00:37 -05:00
konsti cd2fb6fd60
Box `PrioritizedDistribution` (#948)
On top of https://github.com/astral-sh/puffin/pull/947, we can also box
`PrioritizedDistribution`.

In a simple benchmark, this seems to slightly improve performance when
comparing only this commit to main, even though the benchmark is too
noisy to establish significance:

```
$ hyperfine --warmup 30 --runs 300 "target/profiling/main-dev resolve meine_stadt_transparent" "target/profiling/puffin-dev resolve meine_stadt_transparent"
  Benchmark 1: target/profiling/main-dev resolve meine_stadt_transparent
    Time (mean ± σ):      83.6 ms ±   2.0 ms    [User: 77.7 ms, System: 20.0 ms]
    Range (min … max):    81.4 ms …  98.2 ms    300 runs

    Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

  Benchmark 2: target/profiling/puffin-dev resolve meine_stadt_transparent
    Time (mean ± σ):      80.8 ms ±   2.2 ms    [User: 75.4 ms, System: 19.5 ms]
    Range (min … max):    78.6 ms …  98.6 ms    300 runs

    Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

  Summary
    target/profiling/puffin-dev resolve meine_stadt_transparent ran
      1.03 ± 0.04 times faster than target/profiling/main-dev resolve meine_stadt_transparent
```

The effect on type sizes however is considerable ([downstack
PR](https://gist.github.com/konstin/38e6c774db541db46d61f1d4ea6b498f)
vs. [this
PR](https://gist.github.com/konstin/003a77fe7d7d246b0d535e3fc843cb36)):

```patch
--- branch.txt  2024-01-17 14:26:01.826085176 +0100
+++ boxed-prioritized-dist.txt  2024-01-17 14:25:57.101900963 +0100
@@ -1,19 +1,3 @@
-9264 alloc::collections::btree::node::InternalNode<pep440_rs::version::Version, distribution_types::PrioritizedDistribution> align=8
-   9168 data
-     96 edges
-
-9264 alloc::collections::btree::node::InternalNode<pep440_rs::Version, distribution_types::PrioritizedDistribution> align=8
-   9168 data
-     96 edges
-
-9168 alloc::collections::btree::node::LeafNode<pep440_rs::version::Version, distribution_types::PrioritizedDistribution> align=8
-   9064 vals
-     88 keys
-
-9168 alloc::collections::btree::node::LeafNode<pep440_rs::Version, distribution_types::PrioritizedDistribution> align=8
-   9064 vals
-     88 keys
-
 8992 tokio::sync::mpsc::block::Block<hyper::client::dispatch::Envelope<http::request::Request<reqwest::async_impl::body::ImplStream>, http::response::Response<hyper::body::body::Body>>> align=8
    8960 values
      32 header
@@ -74,10 +58,23 @@
          40 __tracing_attr_span
      64 variant Unresumed, Returned, Panicked

+5648 {async fn body@crates/puffin-client/src/registry_client.rs:224:5: 224:30} align=8
+   5647 variant Suspend0
+       5576 __awaitee align=8
+         40 __tracing_attr_span
```
2024-01-19 10:44:41 +01:00
konsti 47fc90d1b3
Reduce stack usage by boxing `File` in `Dist`, `CachePolicy` and large futures (#1004)
This is https://github.com/astral-sh/puffin/pull/947 again but this time
merging into main instead of downstack, sorry for the noise.

---

Windows has a default stack size of 1MB, which makes puffin often fail
with stack overflows. The PR reduces stack size by three changes:

* Boxing `File` in `Dist`, reducing the size from 496 to 240.
* Boxing the largest futures.
* Boxing `CachePolicy`

## Method

Debugging happened on linux using
https://github.com/astral-sh/puffin/pull/941 to limit the stack size to
1MB. Used ran the command below.

```
RUSTFLAGS=-Zprint-type-sizes cargo +nightly build -p puffin-cli -j 1 > type-sizes.txt && top-type-sizes -w -s -h 10 < type-sizes.txt > sizes.txt
```

The main drawback is top-type-sizes not saying what the `__awaitee` is,
so it requires manually looking up with a future with matching size.

When the `brotli` features on `reqwest` is active, a lot of brotli types
show up. Toggling this feature however seems to have no effect. I assume
they are false positives since the `brotli` crate has elaborate control
about allocation. The sizes are therefore shown with the feature off.

## Results

The largest future goes from 12208B to 6416B, the largest type
(`PrioritizedDistribution`, see also #948) from 17448B to 9264B. Full
diff: https://gist.github.com/konstin/62635c0d12110a616a1b2bfcde21304f

For the second commit, i iteratively boxed the largest file until the
tests passed, then with an 800KB stack limit looked through the
backtrace of a failing test and added some more boxing.

Quick benchmarking showed no difference:

```console
$ hyperfine --warmup 2 "target/profiling/main-dev resolve meine_stadt_transparent" "target/profiling/puffin-dev resolve meine_stadt_transparent" 
Benchmark 1: target/profiling/main-dev resolve meine_stadt_transparent
  Time (mean ± σ):      49.2 ms ±   3.0 ms    [User: 39.8 ms, System: 24.0 ms]
  Range (min … max):    46.6 ms …  63.0 ms    55 runs
 
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
 
Benchmark 2: target/profiling/puffin-dev resolve meine_stadt_transparent
  Time (mean ± σ):      47.4 ms ±   3.2 ms    [User: 41.3 ms, System: 20.6 ms]
  Range (min … max):    44.6 ms …  60.5 ms    62 runs
 
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
 
Summary
  target/profiling/puffin-dev resolve meine_stadt_transparent ran
    1.04 ± 0.09 times faster than target/profiling/main-dev resolve meine_stadt_transparent
```
2024-01-19 09:38:36 +00:00
konsti 66e651901e
Add an env var to artificially limit the stack size (#941)
By default, windows has a stack size limit of 1MB which we run against
in debug without any explicit culprit. A new environment variable
`PUFFIN_STACK_SIZE` allows setting an artificially smaller stack size.
2024-01-19 09:34:46 +00:00
Zanie Blue a6a5894901
Add nextest config for retry of flaky test (#996)
We should definitely sort this out per #863 but until then I want to
stop getting false reports of failed CI please and this seems better
than turning off the test entirely.

Alternatively #993
2024-01-19 00:53:12 -05:00
Charlie Marsh 69c72b6fa1
Validate wheel metadata against filename (#1002)
Closes #983.
2024-01-19 05:48:55 +00:00
Charlie Marsh f86d9b1c31
Add tests for missing file errors (#1001) 2024-01-19 05:47:25 +00:00
Charlie Marsh 980e1f6d79
Set explicit Docker permissions (#997) 2024-01-19 05:29:29 +00:00
Charlie Marsh c8285cb5ef
Bump version to v0.0.3 (#999) 2024-01-18 23:39:35 -05:00
Charlie Marsh 9b24fcd306
Remove verbatim URL from path file location (#998)
## Summary

I got confused by why `VerbatimUrl` was on `Path`. Since it's directly
computed from it, I think we should just compute it as-needed. I think
it's also possibly-buggy because the URL is the URL of the _directory_,
not the artifact itself, which differs from other distributions.
2024-01-18 22:40:48 -05:00
Charlie Marsh 6af4eb7a45
Remove `[puffin]` prefix (#989)
And disable the plan job on CI now.
2024-01-19 01:59:06 +00:00
Charlie Marsh 732ef7adb7
Bump version to v0.0.2 (#987)
Bumping the version so that I can test the release process again
(including PyPI publish).
2024-01-18 20:56:09 -05:00
Charlie Marsh fe180804b5
Avoid encoding current version in test output (#988) 2024-01-19 01:50:23 +00:00
Charlie Marsh 3a1cd44fc6
Add Puffin Docker image (#985)
Missing piece for the release.

## Test Plan

Built the image locally:

```shell
❯ docker run 99956098e1f8f04e209dcfc4a0afcee67df1fe8a726c164884e67f035b1a0f42
Usage: puffin [OPTIONS] <COMMAND>

Commands:
  pip    Resolve and install Python packages
  venv   Create a virtual environment
  clean  Clear the cache
  help   Print this message or the help of the given subcommand(s)

Options:
  -q, --quiet                  Do not print any output
  -v, --verbose                Use verbose output
  -n, --no-cache               Avoid reading from or writing to the cache
      --cache-dir <CACHE_DIR>  Path to the cache directory [env: PUFFIN_CACHE_DIR=]
  -h, --help                   Print help
  -V, --version                Print version
```
2024-01-18 20:21:31 -05:00
Charlie Marsh 5e2b715366
Rename `puffin-cli` crate to `puffin` (#976)
## Summary

Like in Ruff, this simplifies a few things.
2024-01-18 19:02:52 -05:00
Charlie Marsh 6cad0f609c
Mark `puffin-dev` as `publish = false` (#975) 2024-01-18 17:20:44 -05:00
Charlie Marsh 8eadca4f8d
Remove unused path method (#974) 2024-01-18 21:59:12 +00:00
Charlie Marsh 04d3474fb4
Set URLs to non-empty in pyproject.toml (#973) 2024-01-18 21:51:09 +00:00
Charlie Marsh 968de30420
Run cargo-dist generate (#972) 2024-01-18 21:22:38 +00:00
Charlie Marsh 59d700ad2d
Run cargo-dist plan on PR (#971) 2024-01-18 16:16:11 -05:00
Charlie Marsh a262936366
Allow file:-relative paths in editable installs (#970)
Supports editable install via (e.g.) `puffin pip install -e file:.`,
which pip seems to support.

Closes #964.
2024-01-18 21:15:42 +00:00
Charlie Marsh a24bfd5418
Remove checked-in requirements file (#969) 2024-01-18 20:46:18 +00:00
Charlie Marsh f9154e8297
Add release workflow (#961)
## Summary

This PR adds a release workflow powered by `cargo-dist`. It's similar to
the version that's PR'd in Ruff
(https://github.com/astral-sh/ruff/pull/9559), with the exception that
it doesn't include the Docker build or the "update dependents" step for
pre-commit.
2024-01-18 15:44:11 -05:00
Charlie Marsh a883de4fb0
Enforce modification freshness checks against virtual environment (#959)
## Summary

This PR is like #957, but for validating the virtual environment, rather
than the cache. So, if you have a local wheel, and you rebuild it, we'll
now correctly uninstall and reinstall it in the virtual environment.
2024-01-18 20:21:16 +00:00
Charlie Marsh 96a61fb351
Remove RFC2047 decoder (#967)
## Summary

- This was inherited from
d719988323/src/metadata.rs (LL78C2-L91C26)
- ...which introduced this code here:
9cd1d43f7c
- ...with the originating issue here:
https://github.com/PyO3/maturin/issues/612
- ...and the upstream issue here:
https://github.com/staktrace/mailparse/issues/50

It seems like the goal was to support Unicode in certain header fields,
but I don't think this is necessary for us. We only use
`get_first_value` for `Requires-Python`, which has to be ASCII, doesn't
it?

In my testing, it seems like the `charset` hack can also be removed. The
tests I copied over actually work without it, which makes me a bit
skeptical.

The main benefit here is that we get to a remove a _big_ dependency
stack, including Chumsky and Stacker and psm which have limited
cross-platform support.
2024-01-18 15:09:45 -05:00
Charlie Marsh f17bad0a75
Mark path-based cache entries as stale during install plan (#957)
## Summary

This is a small correctness improvement that ensures that we avoid using
stale cache entries for local dependencies in the install plan. We
already have some logic like this in the source distribution builder,
but it didn't apply in the install plan, and so we'd end up using stale
wheels.

Specifically, now, if you create a new local wheel, and run `pip sync`,
we'll mark the cache entries as stale and make sure we unzip it and
install it. (If the wheel is _already_ installed, we won't reinstall it
though, which will be a separate change. This is just about reading from
the cache, not the environment.)
2024-01-18 19:13:29 +00:00
Charlie Marsh f852d986f3
Add an incremental resolution benchmark (#954)
## Summary

This adds a benchmark in which we reuse the lockfile, but add a new
dependency to the input requirements.

Running `python -m scripts.bench --poetry --puffin --pip-compile
scripts/requirements/trio.in --benchmark resolve-warm --benchmark
resolve-incremental`:

```text
Benchmark 1: pip-compile (resolve-warm)
  Time (mean ± σ):      1.169 s ±  0.023 s    [User: 0.675 s, System: 0.112 s]
  Range (min … max):    1.129 s …  1.198 s    10 runs

Benchmark 2: poetry (resolve-warm)
  Time (mean ± σ):     610.7 ms ±  10.4 ms    [User: 528.1 ms, System: 60.3 ms]
  Range (min … max):   599.9 ms … 632.6 ms    10 runs

Benchmark 3: puffin (resolve-warm)
  Time (mean ± σ):      19.3 ms ±   0.6 ms    [User: 13.5 ms, System: 13.1 ms]
  Range (min … max):    17.9 ms …  22.1 ms    122 runs

Summary
  'puffin (resolve-warm)' ran
   31.63 ± 1.19 times faster than 'poetry (resolve-warm)'
   60.53 ± 2.37 times faster than 'pip-compile (resolve-warm)'
Benchmark 1: pip-compile (resolve-incremental)
  Time (mean ± σ):      1.554 s ±  0.059 s    [User: 0.974 s, System: 0.130 s]
  Range (min … max):    1.473 s …  1.652 s    10 runs

Benchmark 2: poetry (resolve-incremental)
  Time (mean ± σ):     474.2 ms ±   2.4 ms    [User: 411.7 ms, System: 54.0 ms]
  Range (min … max):   470.6 ms … 477.7 ms    10 runs

Benchmark 3: puffin (resolve-incremental)
  Time (mean ± σ):      28.0 ms ±   1.1 ms    [User: 21.7 ms, System: 14.6 ms]
  Range (min … max):    26.7 ms …  34.4 ms    89 runs

Summary
  'puffin (resolve-incremental)' ran
   16.94 ± 0.67 times faster than 'poetry (resolve-incremental)'
   55.52 ± 3.02 times faster than 'pip-compile (resolve-incremental)'
```
2024-01-18 18:18:37 +00:00
konsti a11744e438
Normalize base python in venv creation (#966)
Fixes #965

We have to canonicalize the interpreter path, otherwise the home is set
to the venv dir instead of the real root. This would make
python-build-standalone fail with the encodings module not being found
because its home is wrong.
2024-01-18 15:32:30 +00:00
konsti 7acde5a9a0
Fix `pep508_rs` doc test (#963)
Since nextest does not run doctests, this did not show up on CI.
2024-01-18 14:24:30 +00:00
konsti 5ec5a3243c
Set miette hook in all of puffin-cli (#962)
Fixes #938
2024-01-18 08:37:26 -05:00