Skip to content

Commit

Permalink
Merge branch 'master' into docs/pipx-first
Browse files Browse the repository at this point in the history
  • Loading branch information
Secrus authored Jul 7, 2023
2 parents d288eda + d31dfa8 commit fbf820f
Show file tree
Hide file tree
Showing 26 changed files with 360 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ repos:
- id: black

- repo: https://github.com/pre-commit/pre-commit
rev: v3.3.2
rev: v3.3.3
hooks:
- id: validate_manifest

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Poetry: Python packaging and dependency management made easy

[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
[![Stable Version](https://img.shields.io/pypi/v/poetry?label=stable)][PyPI Releases]
[![Pre-release Version](https://img.shields.io/github/v/release/python-poetry/poetry?label=pre-release&include_prereleases&sort=semver)][PyPI Releases]
[![Python Versions](https://img.shields.io/pypi/pyversions/poetry)][PyPI]
Expand Down
4 changes: 4 additions & 0 deletions docs/basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ Even if you develop alone, in six months when reinstalling the project you can f
the dependencies installed are still working even if your dependencies released many new versions since then.
(See note below about using the update command.)

{{% warning %}} If you have added the recommended [`[build-system]`]({{< relref "pyproject#poetry-and-pep-517" >}}) section to your project's pyproject.toml then you _can_ successfully install your project and its dependencies into a virtual environment using a command like `pip install -e .`. However, pip will not use the lock file to determine dependency versions as the poetry-core build system is intended for library developers (see next section).
{{% /warning %}}


#### As a library developer

Library developers have more to consider. Your users are application developers, and your library will run in a Python environment you don't control.
Expand Down
13 changes: 9 additions & 4 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,9 @@ As such, `exit` should be used to properly exit the shell and the virtual enviro

## check

The `check` command validates the structure of the `pyproject.toml` file
and returns a detailed report if there are any errors.
The `check` command validates the content of the `pyproject.toml` file
and its consistency with the `poetry.lock` file.
It returns a detailed report if there are any errors.

{{% note %}}
This command is also available as a pre-commit hook. See [pre-commit hooks]({{< relref "pre-commit-hooks#poetry-check">}}) for more information.
Expand All @@ -636,6 +637,10 @@ This command is also available as a pre-commit hook. See [pre-commit hooks]({{<
poetry check
```

### Options

* `--lock`: Verifies that `poetry.lock` exists for the current `pyproject.toml`.

## search

This command searches for packages on a remote index.
Expand All @@ -659,7 +664,7 @@ poetry lock

### Options

* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`
* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`. (**Deprecated**) Use `poetry check --lock` instead.
* `--no-update`: Do not update locked versions, only refresh lock file.

## version
Expand Down Expand Up @@ -951,7 +956,7 @@ poetry self lock

#### Options

* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`
* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`. (**Deprecated**)
* `--no-update`: Do not update locked versions, only refresh lock file.

### self show
Expand Down
30 changes: 30 additions & 0 deletions docs/community.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: "Community"
draft: false
type: docs
layout: single

menu:
docs:
weight: 105
---

# Community

## Badge

For any projects using Poetry, you may add its official badge somewhere prominent like the README.

[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)

**Markdown**
```md
[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
```

**reStructuredText**
```rst
.. image:: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json
:alt: Poetry
:target: https://python-poetry.org/
```
13 changes: 11 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,21 @@ might contain additional Python packages as well.

Create the virtualenv inside the project's root directory.

If not set explicitly, `poetry` by default will create virtual environment under
`{cache-dir}/virtualenvs` or use the `{project-dir}/.venv` directory when one is available.
If not set explicitly, `poetry` by default will create a virtual environment under
`{cache-dir}/virtualenvs` or use the `{project-dir}/.venv` directory if one already exists.

If set to `true`, the virtualenv will be created and expected in a folder named
`.venv` within the root directory of the project.

{{% note %}}
If a virtual environment has already been created for the project under `{cache-dir}/virtualenvs`, setting this variable to `true` will not cause `poetry` to create or use a local virtual environment.

In order for this setting to take effect for a project already in that state, you must delete the virtual environment folder located in `{cache-dir}/virtualenvs`.

You can find out where the current project's virtual environment (if there is one) is stored
with the command `poetry env info --path`.
{{% /note %}}

If set to `false`, `poetry` will ignore any existing `.venv` directory.

### `virtualenvs.options.always-copy`
Expand Down
14 changes: 7 additions & 7 deletions docs/pre-commit-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,16 @@ repos:
`pre-commit autoupdate` updates the `rev` for each repository defined in your `.pre-commit-config.yaml`
to the latest available tag in the default branch.

Poetry follows a branching strategy, where the default branch is the active development branch
and fixes gets back ported to stable branches. New tags are assigned in these stable branches.
Poetry follows a branching strategy where the default branch is the active development branch,
and fixes get backported to stable branches. New tags are assigned in these stable branches.

`pre-commit` does not support such a branching strategy and has decided to not implement
an option, either on the [user side](https://github.com/pre-commit/pre-commit/issues/2512)
or [hook author side](https://github.com/pre-commit/pre-commit/issues/2508), to define a branch for lookup the latest
available tag.
an option, either on the [user's side](https://github.com/pre-commit/pre-commit/issues/2512)
or the [hook author's side](https://github.com/pre-commit/pre-commit/issues/2508), to define a branch for looking
up the latest available tag.

Thus, `pre-commit autoupdate` is not usable for the hooks described here.

You can avoid changing the `rev` to an unexpected value, by using the `--repo` parameter (may be specified multiple
times), to explicit list repositories that should be updated. An option to explicit exclude
You can avoid changing the `rev` to an unexpected value by using the `--repo` parameter (may be specified multiple
times), to explicitly list repositories that should be updated. An option to explicitly exclude
repositories [will not be implemented](https://github.com/pre-commit/pre-commit/issues/1959) into `pre-commit`.
6 changes: 6 additions & 0 deletions docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ The file(s) can be of any format, but if you intend to publish to PyPI keep the
https://packaging.python.org/en/latest/guides/making-a-pypi-friendly-readme/) in
mind. README paths are implicitly relative to `pyproject.toml`.

{{% note %}}
Whether paths are case-sensitive follows platform defaults, but it is recommended to keep cases.

To be specific, you can set `readme = "rEaDmE.mD"` for `README.md` on macOS and Windows, but Linux users can't `poetry install` after cloning your repo. This is because macOS and Windows are case-insensitive and case-preserving.
{{% /note %}}

The contents of the README file(s) are used to populate the [Description
field](https://packaging.python.org/en/latest/specifications/core-metadata/#description-optional)
of your distribution's metadata (similar to `long_description` in setuptools).
Expand Down
2 changes: 1 addition & 1 deletion docs/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ poetry source add --priority=default foo https://foo.bar/simple/
{{% warning %}}

In a future version of Poetry, PyPI will be disabled automatically
if there is at least one custom source configured with another priority than `explicit`.
if at least one custom primary source is configured.
If you are using custom sources in addition to PyPI, you should configure PyPI explicitly
with a certain priority, e.g.

Expand Down
55 changes: 51 additions & 4 deletions src/poetry/console/commands/check.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from cleo.helpers import option

from poetry.console.commands.command import Command


if TYPE_CHECKING:
from pathlib import Path


class CheckCommand(Command):
name = "check"
description = "Checks the validity of the <comment>pyproject.toml</comment> file."

def validate_classifiers(
description = (
"Validates the content of the <comment>pyproject.toml</> file and its"
" consistency with the poetry.lock file."
)

options = [
option(
"lock",
None,
(
"Checks that <comment>poetry.lock</> exists for the current"
" version of <comment>pyproject.toml</>."
),
),
]

def _validate_classifiers(
self, project_classifiers: set[str]
) -> tuple[list[str], list[str]]:
"""Identify unrecognized and deprecated trove classifiers.
Expand Down Expand Up @@ -57,6 +79,17 @@ def validate_classifiers(

return errors, warnings

def _validate_readme(self, readme: str | list[str], poetry_file: Path) -> list[str]:
"""Check existence of referenced readme files"""

readmes = [readme] if isinstance(readme, str) else readme

errors = []
for name in readmes:
if not (poetry_file.parent / name).exists():
errors.append(f"Declared README file does not exist: {name}")
return errors

def handle(self) -> int:
from poetry.factory import Factory
from poetry.pyproject.toml import PyProjectTOML
Expand All @@ -68,10 +101,24 @@ def handle(self) -> int:

# Validate trove classifiers
project_classifiers = set(config.get("classifiers", []))
errors, warnings = self.validate_classifiers(project_classifiers)
errors, warnings = self._validate_classifiers(project_classifiers)
check_result["errors"].extend(errors)
check_result["warnings"].extend(warnings)

# Validate readme (files must exist)
if "readme" in config:
errors = self._validate_readme(config["readme"], poetry_file)
check_result["errors"].extend(errors)

# Verify that lock file is consistent
if self.option("lock") and not self.poetry.locker.is_locked():
check_result["errors"] += ["poetry.lock was not found."]
if self.poetry.locker.is_locked() and not self.poetry.locker.is_fresh():
check_result["errors"] += [
"poetry.lock is not consistent with pyproject.toml. Run `poetry"
" lock [--no-update]` to fix it."
]

if not check_result["errors"] and not check_result["warnings"]:
self.info("All set!")

Expand Down
7 changes: 6 additions & 1 deletion src/poetry/console/commands/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class LockCommand(InstallerCommand):
None,
(
"Check that the <comment>poetry.lock</> file corresponds to the current"
" version of <comment>pyproject.toml</>."
" version of <comment>pyproject.toml</>. (<warning>Deprecated</>) Use"
" <comment>poetry check --lock</> instead."
),
),
]
Expand All @@ -36,6 +37,10 @@ class LockCommand(InstallerCommand):

def handle(self) -> int:
if self.option("check"):
self.line_error(
"<warning>poetry lock --check is deprecated, use `poetry"
" check --lock` instead.</warning>"
)
if self.poetry.locker.is_locked() and self.poetry.locker.is_fresh():
self.line("poetry.lock is consistent with pyproject.toml.")
return 0
Expand Down
6 changes: 3 additions & 3 deletions src/poetry/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,12 @@ def create_pool(
else:
from poetry.repositories.pypi_repository import PyPiRepository

if pool.repositories:
if pool.has_primary_repositories():
io.write_error_line(
"<warning>"
"Warning: In a future version of Poetry, PyPI will be disabled"
" automatically if at least one custom source is configured"
" with another priority than 'explicit'. In order to avoid"
" automatically if at least one custom primary source is"
" configured. In order to avoid"
" a breaking change and make your pyproject.toml forward"
" compatible, add PyPI explicitly via 'poetry source add pypi'."
" By the way, this has the advantage that you can set the"
Expand Down
7 changes: 7 additions & 0 deletions src/poetry/installation/chooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from poetry.config.config import Config
from poetry.config.config import PackageFilterPolicy
from poetry.repositories.http_repository import HTTPRepository
from poetry.utils.wheel import Wheel


Expand Down Expand Up @@ -103,6 +104,12 @@ def _get_links(self, package: Package) -> list[Link]:

assert link.hash_name is not None
h = link.hash_name + ":" + link.hash
if (
h not in hashes
and link.hash_name not in ("sha256", "sha384", "sha512")
and isinstance(repository, HTTPRepository)
):
h = repository.calculate_sha256(link) or h
if h not in hashes:
logger.debug(
"Skipping %s as %s checksum does not match expected value",
Expand Down
38 changes: 20 additions & 18 deletions src/poetry/repositories/http_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,24 +226,7 @@ def _links_to_data(self, links: list[Link], data: PackageInfo) -> dict[str, Any]
and link.hash_name not in ("sha256", "sha384", "sha512")
and hasattr(hashlib, link.hash_name)
):
with self._cached_or_downloaded_file(link) as filepath:
known_hash = (
getattr(hashlib, link.hash_name)() if link.hash_name else None
)
required_hash = hashlib.sha256()

chunksize = 4096
with filepath.open("rb") as f:
while True:
chunk = f.read(chunksize)
if not chunk:
break
if known_hash:
known_hash.update(chunk)
required_hash.update(chunk)

if not known_hash or known_hash.hexdigest() == link.hash:
file_hash = f"{required_hash.name}:{required_hash.hexdigest()}"
file_hash = self.calculate_sha256(link) or file_hash

files.append({"file": link.filename, "hash": file_hash})

Expand All @@ -257,6 +240,25 @@ def _links_to_data(self, links: list[Link], data: PackageInfo) -> dict[str, Any]

return data.asdict()

def calculate_sha256(self, link: Link) -> str | None:
with self._cached_or_downloaded_file(link) as filepath:
known_hash = getattr(hashlib, link.hash_name)() if link.hash_name else None
required_hash = hashlib.sha256()

chunksize = 4096
with filepath.open("rb") as f:
while True:
chunk = f.read(chunksize)
if not chunk:
break
if known_hash:
known_hash.update(chunk)
required_hash.update(chunk)

if not known_hash or known_hash.hexdigest() == link.hash:
return f"{required_hash.name}:{required_hash.hexdigest()}"
return None

def _get_response(self, endpoint: str) -> requests.Response | None:
url = self._url + endpoint
try:
Expand Down
Loading

0 comments on commit fbf820f

Please sign in to comment.