Skip to content

Commit

Permalink
introduce tool.poetry.self.version to define a constraint for the P…
Browse files Browse the repository at this point in the history
…oetry version the project is compatible with (#9547)
  • Loading branch information
radoering committed Jul 14, 2024
1 parent df2a66f commit e300c83
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 2 deletions.
13 changes: 11 additions & 2 deletions docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,18 @@ If you publish your package on PyPI, they will appear in the `Project Links` sec
## `self`

In this section, you can specify requirements for Poetry itself.
For example, you can specify a constraint for the Poetry version that is required
for this project:

You can also specify that a plugin is required for your project:
You can specify that certain plugins are required for your project:
```toml
[tool.poetry.self]
version = ">=2.0"
```

If you are using a Poetry version that is not allowed by this constraint,
an error will be raised.

Further, you can specify that certain plugins are required for your project:

```toml
[tool.poetry.self.plugins]
Expand Down
14 changes: 14 additions & 0 deletions src/poetry/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@

from cleo.io.null_io import NullIO
from packaging.utils import canonicalize_name
from poetry.core.constraints.version import Version
from poetry.core.constraints.version import parse_constraint
from poetry.core.factory import Factory as BaseFactory
from poetry.core.packages.dependency_group import MAIN_GROUP

from poetry.__version__ import __version__
from poetry.config.config import Config
from poetry.exceptions import PoetryException
from poetry.json import validate_object
Expand Down Expand Up @@ -56,6 +59,17 @@ def create_poetry(

base_poetry = super().create_poetry(cwd=cwd, with_groups=with_groups)

if version_str := base_poetry.pyproject.poetry_config.get("self", {}).get(
"version"
):
version_constraint = parse_constraint(version_str)
version = Version.parse(__version__)
if not version_constraint.allows(version):
raise PoetryException(
f"This project requires Poetry {version_constraint},"
f" but you are using Poetry {version}"
)

poetry_file = base_poetry.pyproject_path
locker = Locker(poetry_file.parent / "poetry.lock", base_poetry.pyproject.data)

Expand Down
5 changes: 5 additions & 0 deletions src/poetry/json/schemas/poetry.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
"type": "object",
"description": "Requirements for Poetry itself.",
"properties": {
"version": {
"type": "string",
"description": "The version constraint for Poetry itself.",
"$ref": "#/definitions/dependency"
},
"plugins": {
"type": "object",
"description": "Poetry plugins that are required for this project.",
Expand Down
8 changes: 8 additions & 0 deletions tests/fixtures/self_version_not_ok/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[tool.poetry]
package-mode = false

[tool.poetry.self]
version = "<1.2"

[tool.poetry.dependencies]
python = "^3.8"
8 changes: 8 additions & 0 deletions tests/fixtures/self_version_ok/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[tool.poetry]
package-mode = false

[tool.poetry.self]
version = ">=1.2"

[tool.poetry.dependencies]
python = "^3.8"
8 changes: 8 additions & 0 deletions tests/json/fixtures/self_invalid_version.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.self]
version = 2
3 changes: 3 additions & 0 deletions tests/json/fixtures/self_valid.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.self]
version = ">=2.0"

[tool.poetry.self.plugins]
foo = ">=1.0"
9 changes: 9 additions & 0 deletions tests/json/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ def test_self_valid() -> None:
assert Factory.validate(content) == {"errors": [], "warnings": []}


def test_self_invalid_version() -> None:
toml: dict[str, Any] = TOMLFile(FIXTURE_DIR / "self_invalid_version.toml").read()
content = toml["tool"]["poetry"]
assert Factory.validate(content) == {
"errors": ["data.self.version must be string"],
"warnings": [],
}


def test_self_invalid_plugin() -> None:
toml: dict[str, Any] = TOMLFile(FIXTURE_DIR / "self_invalid_plugin.toml").read()
content = toml["tool"]["poetry"]
Expand Down
18 changes: 18 additions & 0 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from poetry.core.packages.package import Package
from poetry.core.packages.vcs_dependency import VCSDependency

from poetry.__version__ import __version__
from poetry.exceptions import PoetryException
from poetry.factory import Factory
from poetry.plugins.plugin import Plugin
Expand Down Expand Up @@ -230,6 +231,23 @@ def test_create_poetry_non_package_mode(fixture_dir: FixtureDirGetter) -> None:
assert not poetry.is_package_mode


def test_create_poetry_version_ok(fixture_dir: FixtureDirGetter) -> None:
io = BufferedIO()
Factory().create_poetry(fixture_dir("self_version_ok"), io=io)

assert io.fetch_output() == ""
assert io.fetch_error() == ""


def test_create_poetry_version_not_ok(fixture_dir: FixtureDirGetter) -> None:
with pytest.raises(PoetryException) as e:
Factory().create_poetry(fixture_dir("self_version_not_ok"))
assert (
str(e.value)
== f"This project requires Poetry <1.2, but you are using Poetry {__version__}"
)


def test_poetry_with_default_source_legacy(
fixture_dir: FixtureDirGetter, with_simple_keyring: None
) -> None:
Expand Down

0 comments on commit e300c83

Please sign in to comment.