Skip to content

Commit 794e885

Browse files
committed
trust empty requires dist with modern metadata
1 parent 52b113d commit 794e885

File tree

6 files changed

+123
-12
lines changed

6 files changed

+123
-12
lines changed

src/poetry/inspection/info.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import pkginfo
1515

16+
from poetry.core.constraints.version import Version
1617
from poetry.core.factory import Factory
1718
from poetry.core.packages.dependency import Dependency
1819
from poetry.core.packages.package import Package
@@ -57,6 +58,8 @@
5758

5859
PEP517_META_BUILD_DEPS = ["build==1.1.1", "pyproject_hooks==1.0.0"]
5960

61+
DYNAMIC_METADATA_VERSION = Version.parse("2.2")
62+
6063

6164
class PackageInfoError(ValueError):
6265
def __init__(self, path: Path, *reasons: BaseException | str) -> None:
@@ -234,6 +237,43 @@ def to_package(
234237

235238
return package
236239

240+
@classmethod
241+
def _requirements_from_distribution(
242+
cls,
243+
dist: pkginfo.BDist | pkginfo.SDist | pkginfo.Wheel,
244+
) -> list[str] | None:
245+
"""
246+
Helper method to extract package requirements from a `pkginfo.Distribution`
247+
instance.
248+
249+
:param dist: The distribution instance to extract requirements from.
250+
"""
251+
# If the distribution lists requirements, we use those.
252+
#
253+
# If the distribution does not list requirements, but the metadata is new enough
254+
# to specify that this is because there definitely are none: then we return an
255+
# empty list.
256+
#
257+
# If there is a requires.txt, we use that.
258+
if dist.requires_dist:
259+
return list(dist.requires_dist)
260+
261+
if dist.metadata_version is not None:
262+
metadata_version = Version.parse(dist.metadata_version)
263+
if (
264+
metadata_version >= DYNAMIC_METADATA_VERSION
265+
and "Requires-Dist" not in dist.dynamic
266+
):
267+
return []
268+
269+
requires = Path(dist.filename) / "requires.txt"
270+
if requires.exists():
271+
text = requires.read_text(encoding="utf-8")
272+
requirements = parse_requires(text)
273+
return requirements
274+
275+
return None
276+
237277
@classmethod
238278
def _from_distribution(
239279
cls, dist: pkginfo.BDist | pkginfo.SDist | pkginfo.Wheel
@@ -244,15 +284,7 @@ def _from_distribution(
244284
245285
:param dist: The distribution instance to parse information from.
246286
"""
247-
requirements = None
248-
249-
if dist.requires_dist:
250-
requirements = list(dist.requires_dist)
251-
else:
252-
requires = Path(dist.filename) / "requires.txt"
253-
if requires.exists():
254-
text = requires.read_text(encoding="utf-8")
255-
requirements = parse_requires(text)
287+
requirements = cls._requirements_from_distribution(dist)
256288

257289
info = cls(
258290
name=dist.name,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Metadata-Version: 2.2
2+
Name: demo
3+
Version: 0.1.0
4+
Summary: Demo project.
5+
Home-page: https://github.com/demo/demo
6+
Author: Sébastien Eustace
7+
Author-email: [email protected]
8+
License: MIT
9+
Description: UNKNOWN
10+
Platform: UNKNOWN
11+
Dynamic: Requires-Dist
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# this was copied over and modified from orjson project's pyproject.toml
2+
# https://github.com/ijl/orjson/blob/master/pyproject.toml
3+
[project]
4+
name = "demo"
5+
repository = "https://github.com/demo/demo"
6+
7+
[build-system]
8+
build-backend = "maturin"
9+
requires = ["maturin>=0.8.1,<0.9"]
10+
11+
[tool.maturin]
12+
manylinux = "off"
13+
sdist-include = ["Cargo.lock", "json/**/*"]
14+
strip = "on"
15+
16+
[tool.black]
17+
line-length = 88
18+
target-version = ['py36', 'py37', 'py38']
19+
include = '\.pyi?$'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Metadata-Version: 2.3
2+
Name: demo
3+
Version: 0.1.0
4+
Summary: Demo project.
5+
Home-page: https://github.com/demo/demo
6+
Author: Sébastien Eustace
7+
Author-email: [email protected]
8+
License: MIT
9+
Description: UNKNOWN
10+
Platform: UNKNOWN
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# this was copied over and modified from orjson project's pyproject.toml
2+
# https://github.com/ijl/orjson/blob/master/pyproject.toml
3+
[project]
4+
name = "demo"
5+
repository = "https://github.com/demo/demo"
6+
7+
[build-system]
8+
build-backend = "maturin"
9+
requires = ["maturin>=0.8.1,<0.9"]
10+
11+
[tool.maturin]
12+
manylinux = "off"
13+
sdist-include = ["Cargo.lock", "json/**/*"]
14+
strip = "on"
15+
16+
[tool.black]
17+
line-length = 88
18+
target-version = ['py36', 'py37', 'py38']
19+
include = '\.pyi?$'

tests/inspection/test_info.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,30 @@ def test_info_from_setup_cfg(demo_setup_cfg: Path) -> None:
263263

264264

265265
def test_info_no_setup_pkg_info_no_deps(fixture_dir: FixtureDirGetter) -> None:
266-
info = PackageInfo.from_directory(
267-
fixture_dir("inspection") / "demo_no_setup_pkg_info_no_deps",
268-
disable_build=True,
266+
info = PackageInfo.from_metadata_directory(
267+
fixture_dir("inspection") / "demo_no_setup_pkg_info_no_deps"
268+
)
269+
assert info is not None
270+
assert info.name == "demo"
271+
assert info.version == "0.1.0"
272+
assert info.requires_dist is None
273+
274+
275+
def test_info_no_setup_pkg_info_no_deps_for_sure(fixture_dir: FixtureDirGetter) -> None:
276+
info = PackageInfo.from_metadata_directory(
277+
fixture_dir("inspection") / "demo_no_setup_pkg_info_no_deps_for_sure",
269278
)
279+
assert info is not None
280+
assert info.name == "demo"
281+
assert info.version == "0.1.0"
282+
assert info.requires_dist == []
283+
284+
285+
def test_info_no_setup_pkg_info_no_deps_dynamic(fixture_dir: FixtureDirGetter) -> None:
286+
info = PackageInfo.from_metadata_directory(
287+
fixture_dir("inspection") / "demo_no_setup_pkg_info_no_deps_dynamic",
288+
)
289+
assert info is not None
270290
assert info.name == "demo"
271291
assert info.version == "0.1.0"
272292
assert info.requires_dist is None

0 commit comments

Comments
 (0)