Commit Graph

54 Commits

Author SHA1 Message Date
Zanie dce07c2ca7 Bump packse 2024-01-26 12:40:02 -06:00
Zanie ecba550152 Add assertions that `pip compile` scenario test matches expected outcome 2024-01-26 12:40:02 -06:00
Zanie Blue 5cc4e5d31e
Add `pip compile` test where specific Python versions are available on the system (#1111)
Extends https://github.com/astral-sh/puffin/pull/1106 with the scenario
from https://github.com/zanieb/packse/pull/95 which tests that `pip
compile` will use the matching system Python version for builds when
available
2024-01-26 18:38:24 +00:00
Zanie Blue 91f421cf97
Do not allow `pip compile` scenario tests to discover other Python versions (#1106)
In https://github.com/astral-sh/puffin/pull/1040 we broke the pip
compile scenarios designed to test failure when a required Python
version is not available — resolution succeeded because all of the
Python versions were available in CI. Following #1105 we have the
ability to isolate tests from Python versions available in the system.
Here, we limit the scenarios to only the Python version in the current
environment, restoring our ability to test the error messages.

With https://github.com/zanieb/packse/pull/95, we will be able to
specify scenarios with access to additional system Python versions. This
will allow us to include test coverage where resolution can succeed by
using a version available elsewhere on the system. See #1111 for this
follow-up.
2024-01-26 18:18:15 +00:00
Zanie Blue 21577ad002
Add bootstrapping and isolation of development Python versions (#1105)
Replaces https://github.com/astral-sh/puffin/pull/1068 and #1070 which
were more complicated than I wanted.

- Introduces a `.python-versions` file which defines the Python versions
needed for development
- Adds a Bash script at `scripts/bootstrap/install` which installs the
required Python versions from `python-build-standalone` to `./bin`
- Checks in a `versions.json` file with metadata about available
versions on each platform and a `fetch-version` Python script derived
from `rye` for updating the versions
- Updates CI to use these Python builds instead of the `setup-python`
action
- Updates to the latest packse scenarios which require Python 3.8+
instead of 3.7+ since we cannot use 3.7 anymore and includes new test
coverage of patch Python version requests
- Adds a `PUFFIN_PYTHON_PATH` variable to prevent lookup of system
Python versions for isolation during development

Tested on Linux (via CI) and macOS (locally) — presumably it will be a
bit more complicated to do proper Windows support.
2024-01-26 12:12:48 -06:00
konsti f1d3b08c12
Add missing version to pip sync test (#1121)
The test started failing due to a newer version on pypi.
2024-01-26 13:36:25 +00:00
Charlie Marsh 361a2039d2
Add `--no-annotate` and `--no-header` flags (#1117)
Closes #1107.
Closes #1108.
2024-01-26 12:14:18 +00:00
Charlie Marsh 7755f986c3
Support extras in editable requirements (#1113)
## Summary

This PR adds support for requirements like `-e .[d]`.

Closes #1091.
2024-01-26 12:07:51 +00:00
Charlie Marsh 57c116ee9a
Move Black editable to flit backend (#1114)
I ran into a bug in PDM that's making it impossible to use the Black
example for extras: https://github.com/pdm-project/pdm/issues/2591.

I've confirmed that Flit handles it correctly.
2024-01-25 19:54:54 -05:00
Zanie Blue 3a05ef5285
Add venv tests for missing Python versions (#1096)
These demonstrate some lackluster error messages.
2024-01-25 13:57:05 -06:00
Charlie Marsh f4939e50a6
Remove UNC prefixes on Windows (#1086)
## Summary

This PR adds a `NormalizedDisplay` trait that we can use for user-facing
paths, to strip the UNC prefix on Windows.

On other platforms, the implementation is a no-op (vs. `Display`).

I audited all usages of `.display()`, and changed any that were
user-facing, either via `println!` or `eprintln!`, or by way of being
included in error messages. I did _not_ change uses that were only in
tests or only went to tracing.

Closes https://github.com/astral-sh/puffin/issues/1084.
2024-01-25 11:44:22 -05:00
Zanie Blue ed1ac640b9
Consolidate `UnusableDependencies` into a generic `Unavailable` incompatibility (#1088)
Requires https://github.com/zanieb/pubgrub/pull/20

In short, `UnusableDependencies` can be generalized into `Unavailable`
which encompasses incompatibilities where a package range which is
unusable for some inherent reason as well as when its dependencies are
unusable. We can eventually use this to track more incompatibilities in
the solver. I made the reason string required because I can't see a case
where we should leave it out.

Additionally, this improves the display of conflicts in the root
requirements.
2024-01-24 22:10:44 -06:00
Zanie Blue 091f8e09ff
Use a cache directory for venv tests (#1089) 2024-01-24 22:09:37 -06:00
Zanie Blue 0019fe71f6
Add warning when target version does not match build version (#1072)
Follow-up to https://github.com/astral-sh/puffin/pull/1040 adding a
user-facing warning when we cannot build with their requested version.

e.g.

```
❯ cargo run -- pip compile requirements.in --python-version 3.11.4 --no-build
Resolved 8 packages in 483ms
❯ cargo run -- pip compile requirements.in --python-version 3.11.4
warning: The requested Python version 3.11.4 is not available; 3.11.7 will be used to build dependencies instead.
Resolved 8 packages in 71ms
❯ cargo run -- pip compile requirements.in --python-version 3.11
Resolved 8 packages in 71ms
```
2024-01-24 13:42:19 -06:00
konsti 2e0ce70d13
Initial windows support (#940)
## Summary

First batch of changes for windows support. Notable changes:

* Fixes all compile errors and added windows specific paths.
* Working venv creation on windows, both from a base interpreter and
from a venv. This requires querying `stdlib` from the sysconfig paths to
find the launcher.
* Basic url/path conversion handling for windows.
* `if cfg!(...)` instead of `#[cfg()]`. This should make it easier to
keep everything compiling across platforms.

## Outlook

Test summary: 402 tests run: 299 passed (15 slow), 103 failed, 1 skipped

There are various reason for the remaining test failure:
* Windows-specific colorama and tzdata dependencies that change the
snapshot slightly. This is by far the biggest batch.
* Some url-path handling issues. I fixed some in the PR, some remain.
* Lack of the latest python patch versions for older pythons on my
machine, since there are no builds for windows and we need to register
them in the registry for them to be picked up for `py --list-paths` (CC
@zanieb RE #1070).
* Lack of entrypoint launchers.
* ... likely more
2024-01-24 18:27:49 +01:00
Zanie Blue ea4ab29bad
Prefer target Python version over current version for builds (#1040)
Extends #1029 
Closes https://github.com/astral-sh/puffin/issues/1038

Instead of always using the current Python version for builds when a
target version is provided, we will do our best to use a compatible
Python version for builds.

Removes behavior where Python versions without patch versions were
always assumed to be the latest known patch version (previously
discussed in https://github.com/astral-sh/puffin/pull/534). While this
was convenient for resolutions which include packages which require
minimum patch versions e.g. `requires-python=">=3.7.4"`, it conflicts
with the idea that the target Python version you provide is the
_minimum_ compatible version. Additionally, it complicates interpreter
lookup as we cannot tell if the user has asked for that specific patch
version or not.
2024-01-24 11:12:02 -06:00
Charlie Marsh 0519375bd6
Remove some unused dependencies (#1077) 2024-01-24 11:58:21 -05:00
konsti 411613a24e
No python prefix in packse scenarios (#1066)
In windows, `python3.9` and `python3.11` are not in `PATH`. Instead, we
should pass only the python version to `puffin venv -p` in packse
scenarios (#1039).
2024-01-24 11:22:48 +00:00
Charlie Marsh 1b3a3f4e80
Add `--refresh` behavior to the cache (#1057)
## Summary

This PR is an alternative approach to #949 which should be much safer.
As in #949, we add a `Refresh` policy to the cache. However, instead of
deleting entries from the cache the first time we read them, we now
check if the entry is sufficiently new (created after the start of the
command) if the refresh policy applies. If the entry is stale, then we
avoid reading it and continue onward, relying on the cache to
appropriately overwrite based on "new" data. (This relies on the
preceding PRs, which ensure the cache is append-only, and ensure that we
can atomically overwrite.)

Unfortunately, there are just a lot of paths through the cache, and
didn't data is handled with different policies, so I really had to go
through and consider the "right" behavior for each case. For example,
the HTTP requests can use `max-age=0, must-revalidate`. But for the
routes that are based on filesystem modification, we need to do
something slightly different.

Closes #945.
2024-01-23 18:30:26 -05:00
Zanie Blue 1f0a21d127
Write an `Into<anstream::ColorChoice>` implementation for more idiomatic code (#1064)
Follow-up to #1049
2024-01-23 15:43:16 +00:00
konsti 1131341cbc
Support more formats in `puffin venv`, incl. windows support (#1039)
Mirroring `virtualenv -p` and driven by the lack of `pythonx.y` in
`PATH` on windows, this PR adds `-p x.y` support to `puffin venv` (first
commit).

Supported formats:
* NEW: `-p 3.10` searches for an installed Python 3.10 (Looking for
`python3.10` on linux/mac).
  Specifying a patch version is not supported
* `-p python3.10` or `-p python.exe` looks for a binary in `PATH`
* `-p /home/ferris/.local/bin/python3.10` uses this exact Python

In the second commit, we add python interpreter search on windows using
`py --list-paths`. On windows, all python are called `python.exe` so the
unix trick of looking for `python{}.{}` in `PATH` doesn't work. Instead,
we ask the python launcher for windows to tell us about all installed
packages. We should eventually migrate this to [PEP
514](https://peps.python.org/pep-0514/) by reading the registry entries
ourselves.
2024-01-23 15:35:07 +00:00
Charlie Marsh cb04fa4496
Hide `--exclude-newer` from the command line (#1058)
This exists for our own test suite.
2024-01-23 00:29:47 -05:00
Zanie Blue 5db81c7caa
Add `--color always|never|auto` interface (#1049)
Extends #1048 interface providing a more general interface that I think
should be standard.

Allows forcing colors to be on _or_ off. e.g. `NO_COLOR=1 pip install
pip-tools --color always` would be colored.

Hides the `--no-color` option as it only exists for compatibility (and
seems better than throwing an error when people assume it will exist).

Has a nice side-effect of documenting our coloring behaviors e.g.

```
--color <COLOR>
    Control colors in output
    
    [default: auto]

    Possible values:
    - auto:   Enables colored output only when the output is going to a terminal or TTY with support
    - always: Enables colored output regardless of the detected environment
    - never:  Disables colored output
```
2024-01-22 23:01:36 -06:00
Zanie Blue a9a7b0069b
Add `--force-reinstall` alias for `--reinstall` to match pip interface (#1045)
Tested with `cargo run -- pip install pip-tools --force-reinstall`.

The alias is hidden.
2024-01-22 22:59:43 -06:00
Zanie Blue a87e071b5e
Add `--no-color` support for `pip` compatibility (#1048)
Adds `--no-color` as provided by `pip`.

See #1049 for follow-up.
2024-01-22 22:56:51 -06:00
Zanie Blue c06bc335c4
Fix failing test cases (#1047)
These tests from #1041 failing on `main`
https://github.com/astral-sh/puffin/actions/runs/7616995716/job/20745019216
due to conflict with #1042
2024-01-22 21:31:12 +00:00
Zanie Blue a2efd74209
Add complex Python requirement scenarios (#1041)
Follows #1011 with some more scenarios
2024-01-22 14:31:06 -06:00
Zanie Blue 89eb8547ce
Fix missing comma before conclusions (#1042)
Closes https://github.com/astral-sh/puffin/issues/1010
2024-01-22 13:31:09 -06:00
Zanie Blue e21948f353
Improve display of Python versions (#1029)
In https://github.com/astral-sh/puffin/pull/986 there was some confusion
about what these values are set to and I noticed that we never actually
display the target version being used for a resolution.

- Consistently display the Python interpreter being used, i.e. make it
clear that we are referring the the interpreter/installed Python version
and always show the version number
- Display the target Python version during solving
2024-01-22 18:46:18 +00:00
Charlie Marsh b0e73d796c
Add support for PyPy wheels (#1028)
## Summary

This PR adds support for PyPy wheels by changing the compatible tags
based on the implementation name and version of the current interpreter.

For now, we only support CPython and PyPy, and explicitly error out when
given other interpreters. (Is this right? Should we just fallback to
CPython tags...? Or skip the ABI-specific tags for unknown
interpreters?)

The logic is based on
4d85340613/src/packaging/tags.py (L247).
Note, however, that `packaging` uses the `EXT_SUFFIX` variable from
`sysconfig`... Instead, I looked at the way that PyPy formats the tags,
and recreated them based on the Python and implementation version. For
example, PyPy wheels look like
`cchardet-2.1.7-pp37-pypy37_pp73-win_amd64.whl` -- so that's `pp37` for
PyPy with Python version 3.7, and then `pypy37_pp73` for PyPy with
Python version 3.7 and PyPy version 7.3.

Closes https://github.com/astral-sh/puffin/issues/1013.

## Test Plan

I tested this manually, but I couldn't find macOS universal PyPy
wheels... So instead I added `cchardet` to a `requirements.in`, ran
`cargo run pip sync requirements.in --index-url
https://pypy.kmtea.eu/simple --verbose`, and added logging to verify
that the platform tags matched (even if the architecture didn't).
2024-01-22 14:22:27 +00:00
Charlie Marsh 145ba0e5ab
Allow relative paths in requirements.txt (#1027)
This PR attempts to fix a common footgun in `requirements.txt` files.
Previously, to provide a file, you had to use `package_name @
file:///Users/crmarsh/...` -- in other words, an absolute path.

Now, these requirements follow the exact same rules as editables, so you
can do:
```
package_name @ ./file.zip
```

And similar.

The way the parsing is setup, this is intentionally _not_ supported when
reading metadata -- only when parsing `requirements.txt` directly.

Closes #984.
2024-01-22 14:20:30 +00:00
Charlie Marsh db0c76c4ba
Improve `requirements-txt` error formatting (#1026)
- Wrap filename in quotes
- Only show the start position (I think the end is a bit noisy)
2024-01-22 13:42:17 +00:00
Charlie Marsh b9bee013ce
Use full Python version for installed version (#1033)
## Summary

`interpreter.version()` returns the `python_full_version`, but the
marker variant uses `python_version` instead of `python_full_version` --
so it's omitting the patch.
2024-01-22 00:44:39 -06:00
Zanie Blue 6202c9e1b5
Use current and requested Python versions in `requires-python` incompatibility errors (#986)
Closes https://github.com/astral-sh/puffin/issues/806
2024-01-22 00:32:02 -06:00
Charlie Marsh 23f73592b1
Add test to avoid invalidating virtualenv (#1031)
## Summary

I think if we used symlinks (instead of hardlinks), this test would fail
-- so it's worth including.
2024-01-21 19:53:58 -05:00
Charlie Marsh 540442b8de
Treat missing package name error as an unsupported requirement (#1025)
## Summary

Based on user feedback. Calling it a "parse error" is misleading, since
this is really something we don't support, but that users can work
around.
2024-01-21 19:53:10 -05:00
Zanie Blue 4026710189
Add scenario tests for `pip-compile` (#1011)
e.g. for scenarios that test resolution _without_ installation.

This refactors the `update` script to generate scenario test files for
`pip compile` _and_ `pip install`. We don't overlap scenarios to save
time. We only generate `pip compile` test cases for scenarios we cannot
represent with `pip install` e.g. a `--python-version` override.

The _one_ scenario I added happened to reveal a bug in our resolver
where we were incorrectly filtering versions by the installed version
when wheels were available. Per the comment at
https://github.com/astral-sh/puffin/issues/883#issuecomment-1890773112,
we should _only_ need to check for a compatible installed Python version
when using a different _target_ Python version if we need to build a
source distribution.
53bce68400
resolves this by removing the excessive constraints — the correct Python
version incompatibilities are applied elsewhere.
2024-01-21 17:47:42 -06:00
Charlie Marsh d9cc9dbf88
Improve error message when editable requirement doesn't exist (#1024)
Making these a lot clearer in the common case by reducing the depth of
the error.
2024-01-20 12:59:18 -05:00
Charlie Marsh b3954f2449
Enable PowerPC builds (#1017)
Closes #1015.
2024-01-19 17:29:11 -05:00
Charlie Marsh 459c2abc81
Avoid canonicalizing paths in `requirements-txt` (#1019)
## Summary

When you specify an editable that doesn't exist, it should error, but
not in the parser -- the error should be downstream.
2024-01-19 16:28:04 -05: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 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
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