Skip to content

Commit f561089

Browse files
committed
introduce tool.poetry.requires-poetry to define a constraint for the Poetry version the project is compatible with (python-poetry#9547)
1 parent a6fe66c commit f561089

File tree

9 files changed

+73
-0
lines changed

9 files changed

+73
-0
lines changed

docs/pyproject.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,17 @@ any custom url in the `urls` section.
843843

844844
If you publish your package on PyPI, they will appear in the `Project Links` section.
845845

846+
## `requires-poetry`
847+
848+
A constraint for the Poetry version that is required for this project.
849+
If you are using a Poetry version that is not allowed by this constraint,
850+
an error will be raised.
851+
852+
```toml
853+
[tool.poetry]
854+
requires-poetry = ">=2.0"
855+
```
856+
846857
## `requires-plugins`
847858

848859
In this section, you can specify that certain plugins are required for your project:

src/poetry/factory.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010

1111
from cleo.io.null_io import NullIO
1212
from packaging.utils import canonicalize_name
13+
from poetry.core.constraints.version import Version
14+
from poetry.core.constraints.version import parse_constraint
1315
from poetry.core.factory import Factory as BaseFactory
1416
from poetry.core.packages.dependency_group import MAIN_GROUP
1517

18+
from poetry.__version__ import __version__
1619
from poetry.config.config import Config
1720
from poetry.exceptions import PoetryError
1821
from poetry.json import validate_object
@@ -56,6 +59,15 @@ def create_poetry(
5659

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

62+
if version_str := base_poetry.local_config.get("requires-poetry"):
63+
version_constraint = parse_constraint(version_str)
64+
version = Version.parse(__version__)
65+
if not version_constraint.allows(version):
66+
raise PoetryError(
67+
f"This project requires Poetry {version_constraint},"
68+
f" but you are using Poetry {version}"
69+
)
70+
5971
poetry_file = base_poetry.pyproject_path
6072
locker = Locker(poetry_file.parent / "poetry.lock", base_poetry.pyproject.data)
6173

src/poetry/json/schemas/poetry.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"type": "object",
55
"required": [],
66
"properties": {
7+
"requires-poetry": {
8+
"type": "string",
9+
"description": "The version constraint for Poetry itself.",
10+
"$ref": "#/definitions/dependency"
11+
},
712
"requires-plugins": {
813
"type": "object",
914
"description": "Poetry plugins that are required for this project.",
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[tool.poetry]
2+
package-mode = false
3+
requires-poetry = "<1.2"
4+
5+
[tool.poetry.dependencies]
6+
python = "^3.8"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[tool.poetry]
2+
package-mode = false
3+
requires-poetry = ">=1.2"
4+
5+
[tool.poetry.dependencies]
6+
python = "^3.8"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[tool.poetry]
2+
name = "foobar"
3+
version = "0.1.0"
4+
description = ""
5+
authors = ["Your Name <[email protected]>"]
6+
requires-poetry = 2

tests/json/fixtures/self_valid.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name = "foobar"
33
version = "0.1.0"
44
description = ""
55
authors = ["Your Name <[email protected]>"]
6+
requires-poetry = ">=2.0"
67

78
[tool.poetry.requires-plugins]
89
foo = ">=1.0"

tests/json/test_schema.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ def test_self_valid() -> None:
3939
assert Factory.validate(toml) == {"errors": [], "warnings": []}
4040

4141

42+
def test_self_invalid_version() -> None:
43+
toml: dict[str, Any] = TOMLFile(FIXTURE_DIR / "self_invalid_version.toml").read()
44+
assert Factory.validate(toml) == {
45+
"errors": ["data.requires-poetry must be string"],
46+
"warnings": [],
47+
}
48+
49+
4250
def test_self_invalid_plugin() -> None:
4351
toml: dict[str, Any] = TOMLFile(FIXTURE_DIR / "self_invalid_plugin.toml").read()
4452
assert Factory.validate(toml) == {

tests/test_factory.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from poetry.core.packages.package import Package
1515
from poetry.core.packages.vcs_dependency import VCSDependency
1616

17+
from poetry.__version__ import __version__
1718
from poetry.exceptions import PoetryError
1819
from poetry.factory import Factory
1920
from poetry.plugins.plugin import Plugin
@@ -230,6 +231,23 @@ def test_create_poetry_non_package_mode(fixture_dir: FixtureDirGetter) -> None:
230231
assert not poetry.is_package_mode
231232

232233

234+
def test_create_poetry_version_ok(fixture_dir: FixtureDirGetter) -> None:
235+
io = BufferedIO()
236+
Factory().create_poetry(fixture_dir("self_version_ok"), io=io)
237+
238+
assert io.fetch_output() == ""
239+
assert io.fetch_error() == ""
240+
241+
242+
def test_create_poetry_version_not_ok(fixture_dir: FixtureDirGetter) -> None:
243+
with pytest.raises(PoetryError) as e:
244+
Factory().create_poetry(fixture_dir("self_version_not_ok"))
245+
assert (
246+
str(e.value)
247+
== f"This project requires Poetry <1.2, but you are using Poetry {__version__}"
248+
)
249+
250+
233251
@pytest.mark.parametrize(
234252
"project",
235253
("with_primary_source_implicit", "with_primary_source_explicit"),

0 commit comments

Comments
 (0)