Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: support multiple hash algorithms #6490

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ This ensures that everyone using the library will get the same versions of the d

If there is no `poetry.lock` file, Poetry will create one after dependency resolution.

If you want to exclude one or more dependency group for the installation, you can use
If you want to exclude one or more dependency groups for the installation, you can use
the `--without` option.

```bash
Expand Down Expand Up @@ -201,6 +201,12 @@ poetry install -E mysql -E pgsql
poetry install --all-extras
```

Extras are not sensitive to `--sync`. Any extras not specified will always be removed.

```bash
poetry install --extras "A B" # C is removed
```

By default `poetry` will install your project's package every time you run `install`:

```bash
Expand Down
12 changes: 9 additions & 3 deletions docs/managing-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,9 @@ to remove packages from a specific group:
poetry remove mkdocs --group docs
```


## Synchronizing dependencies

Poetry supports what's called dependency synchronization. What this does is ensuring
Poetry supports what's called dependency synchronization. Dependency synchronization ensures
that the locked dependencies in the `poetry.lock` file are the only ones present
in the environment, removing anything that's not necessary.

Expand All @@ -198,7 +197,8 @@ poetry install --sync
```

The `--sync` option can be combined with any [dependency groups]({{< relref "#dependency-groups" >}}) related options
to synchronize the environment with specific groups.
to synchronize the environment with specific groups. Note that extras are separate. Any
extras not selected for install are always removed, regardless of `--sync`.

```bash
poetry install --without dev --sync
Expand All @@ -209,3 +209,9 @@ poetry install --only dev
{{% note %}}
The `--sync` option replaces the `--remove-untracked` option which is now deprecated.
{{% /note %}}

## Layering optional groups

When you omit the `--sync` option, you can install any subset of optional groups without removing
those that are already installed. This is very useful, for example, in multi-stage
Docker builds, where you run `poetry install` multiple times in different build stages.
6 changes: 5 additions & 1 deletion docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,11 @@ poetry install --extras "mysql pgsql"
poetry install -E mysql -E pgsql
```

Or, you can install all extras with the `--all-extras` option:
Any extras you don't specify will be removed. Note this behavior is different from
[optional dependency groups]({{< relref "managing-dependencies#optional-groups" >}}) not
selected for install, e.g. those not specified via `install --with`.

You can install all extras with the `--all-extras` option:

```bash
poetry install --all-extras
Expand Down
16 changes: 9 additions & 7 deletions src/poetry/installation/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,16 +658,18 @@ def _download_link(self, operation: Install | Update, link: Link) -> Path:
@staticmethod
def _validate_archive_hash(archive: Path, package: Package) -> str:
file_dep = FileDependency(package.name, archive)
archive_hash: str = "sha256:" + file_dep.hash()
known_hashes = {f["hash"] for f in package.files}

if archive_hash not in known_hashes:
raise RuntimeError(
f"Hash for {package} from archive {archive.name} not found in"
f" known hashes (was: {archive_hash})"
)
for known_hash in known_hashes:
hash_name, known_hash_value = known_hash.split(":", 1)
archive_hash_value = file_dep.hash(hash_name=hash_name)

if known_hash_value == archive_hash_value:
return f"{hash_name}:{archive_hash_value}"

return archive_hash
raise RuntimeError(
f"Hash for {package} from archive {archive.name} not found in known hashes"
)

def _download_archive(self, operation: Install | Update, link: Link) -> Path:
response = self._authenticator.request(
Expand Down
11 changes: 10 additions & 1 deletion tests/installation/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,13 +643,22 @@ def test_executor_should_write_pep610_url_references_for_git_with_subdirectories
)


@pytest.mark.parametrize(
"file_hash",
[
"sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a",
"md5:15507846fd4299596661d0197bfb4f90",
"sha512:44cfa6b8696e5008c1c4dfe32c52a8b6511c261d8f3a25882366c0718eb42a17da5e4b9196623597661871be65c48e613d8f5c50a5c5c827e0efbf8b612fe5be", # noqa: E501
],
)
def test_executor_should_use_cached_link_and_hash(
tmp_venv: VirtualEnv,
pool: Pool,
config: Config,
io: BufferedIO,
mocker: MockerFixture,
fixture_dir: FixtureDirGetter,
file_hash: str,
):
link_cached = fixture_dir("distributions") / "demo-0.1.0-py2.py3-none-any.whl"

Expand All @@ -663,7 +672,7 @@ def test_executor_should_use_cached_link_and_hash(
package.files = [
{
"file": "demo-0.1.0-py2.py3-none-any.whl",
"hash": "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a", # noqa: E501
"hash": file_hash,
}
]

Expand Down