Skip to content

Commit 1ad5f68

Browse files
authored
Merge pull request #43 from jreese/pep621
Initial support for PEP 621 metadata with Flit
2 parents 763f615 + f072c48 commit 1ad5f68

File tree

5 files changed

+163
-14
lines changed

5 files changed

+163
-14
lines changed

dowsing/flit.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import tomlkit
55
from setuptools import find_packages
66

7-
from .types import BaseReader, Distribution
7+
from .pep621 import Pep621Reader
8+
from .types import Distribution
89

910

10-
class FlitReader(BaseReader):
11+
class FlitReader(Pep621Reader):
1112
def __init__(self, path: Path):
1213
self.path = path
1314

@@ -21,12 +22,12 @@ def get_metadata(self) -> Distribution:
2122
pyproject = self.path / "pyproject.toml"
2223
doc = tomlkit.parse(pyproject.read_text())
2324

24-
d = Distribution()
25-
d.metadata_version = "2.1"
26-
d.project_urls = {}
27-
d.entry_points = {}
25+
d = self.get_pep621_metadata()
26+
d.entry_points = dict(d.entry_points) or {}
2827

29-
for k, v in doc["tool"]["flit"]["metadata"].items():
28+
flit = doc.get("tool", {}).get("flit", {})
29+
metadata = flit.get("metadata", {})
30+
for k, v in metadata.items():
3031
# TODO description-file -> long_description
3132
# TODO home-page -> urls
3233
# TODO requires -> requires_dist
@@ -52,10 +53,10 @@ def get_metadata(self) -> Distribution:
5253
if k2 in d:
5354
setattr(d, k2, v)
5455

55-
for k, v in doc["tool"]["flit"]["metadata"].get("urls", {}).items():
56+
for k, v in metadata.get("urls", {}).items():
5657
d.project_urls[k] = v
5758

58-
for k, v in doc["tool"]["flit"].get("scripts", {}).items():
59+
for k, v in flit.get("scripts", {}).items():
5960
d.entry_points[k] = v
6061

6162
# TODO extras-require
@@ -72,8 +73,7 @@ def _get_requires(self) -> Sequence[str]:
7273
7374
https://github.com/takluyver/flit/issues/141
7475
"""
75-
pyproject = self.path / "pyproject.toml"
76-
doc = tomlkit.parse(pyproject.read_text())
77-
seq = doc["tool"]["flit"]["metadata"].get("requires", ())
76+
dist = self.get_metadata()
77+
seq = dist.requires_dist
7878
assert isinstance(seq, (list, tuple))
7979
return seq

dowsing/pep621.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import tomlkit
2+
from setuptools import find_packages
3+
4+
from .types import BaseReader, Distribution
5+
6+
7+
class Pep621Reader(BaseReader):
8+
def get_pep621_metadata(self) -> Distribution:
9+
pyproject = self.path / "pyproject.toml"
10+
doc = tomlkit.parse(pyproject.read_text())
11+
12+
d = Distribution()
13+
d.metadata_version = "2.1"
14+
d.project_urls = {}
15+
d.entry_points = {}
16+
d.requires_dist = []
17+
d.packages = []
18+
d.packages_dict = {}
19+
20+
table = doc.get("project", None)
21+
if table:
22+
for k, v in table.items():
23+
if k == "name":
24+
if (self.path / f"{v}.py").exists():
25+
d.py_modules = [v]
26+
else:
27+
d.packages = find_packages(
28+
self.path.as_posix(), include=(f"{v}.*")
29+
)
30+
d.packages_dict = {i: i.replace(".", "/") for i in d.packages}
31+
elif k == "license":
32+
if "text" in v:
33+
v = v["text"]
34+
elif "file" in v:
35+
v = f"file: {v['file']}"
36+
else:
37+
raise ValueError("no known license field values")
38+
elif k == "dependencies":
39+
k = "requires_dist"
40+
elif k == "optional-dependencies":
41+
pass
42+
elif k == "urls":
43+
d.project_urls.update(v)
44+
45+
k2 = k.replace("-", "_")
46+
if k2 in d:
47+
setattr(d, k2, v)
48+
49+
return d

dowsing/tests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .flit import FlitReaderTest
33
from .maturin import MaturinReaderTest
44
from .pep517 import Pep517Test
5+
from .pep621 import Pep621ReaderTest
56
from .poetry import PoetryReaderTest
67
from .setuptools import SetuptoolsReaderTest
78
from .setuptools_metadata import SetupArgsTest
@@ -12,6 +13,7 @@
1213
"FlitReaderTest",
1314
"MaturinReaderTest",
1415
"Pep517Test",
16+
"Pep621ReaderTest",
1517
"PoetryReaderTest",
1618
"SetuptoolsReaderTest",
1719
"WriterTest",

dowsing/tests/flit.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ def test_simplest(self) -> None:
2323
# handle missing metadata appropriately.
2424

2525
r = FlitReader(dp)
26-
self.assertEqual((), r.get_requires_for_build_sdist())
27-
self.assertEqual((), r.get_requires_for_build_wheel())
26+
self.assertEqual([], r.get_requires_for_build_sdist())
27+
self.assertEqual([], r.get_requires_for_build_wheel())
2828
md = r.get_metadata()
2929
self.assertEqual("Name", md.name)
3030

@@ -69,3 +69,44 @@ def test_normal(self) -> None:
6969
},
7070
md.asdict(),
7171
)
72+
73+
def test_pep621(self) -> None:
74+
with volatile.dir() as d:
75+
dp = Path(d)
76+
(dp / "pyproject.toml").write_text(
77+
"""\
78+
[build-system]
79+
requires = ["flit_core >=2,<4"]
80+
build-backend = "flit_core.buildapi"
81+
82+
[project]
83+
name = "foo"
84+
dependencies = ["abc", "def"]
85+
86+
[project.urls]
87+
Foo = "https://"
88+
"""
89+
)
90+
(dp / "foo").mkdir()
91+
(dp / "foo" / "tests").mkdir()
92+
(dp / "foo" / "__init__.py").write_text("")
93+
(dp / "foo" / "tests" / "__init__.py").write_text("")
94+
95+
r = FlitReader(dp)
96+
# Notably these do not include flit itself; that's handled by
97+
# dowsing.pep517
98+
self.assertEqual(["abc", "def"], r.get_requires_for_build_sdist())
99+
self.assertEqual(["abc", "def"], r.get_requires_for_build_wheel())
100+
md = r.get_metadata()
101+
self.assertEqual("foo", md.name)
102+
self.assertEqual(
103+
{
104+
"metadata_version": "2.1",
105+
"name": "foo",
106+
"packages": ["foo", "foo.tests"],
107+
"packages_dict": {"foo": "foo", "foo.tests": "foo/tests"},
108+
"requires_dist": ["abc", "def"],
109+
"project_urls": {"Foo": "https://"},
110+
},
111+
md.asdict(),
112+
)

dowsing/tests/pep621.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import unittest
2+
from pathlib import Path
3+
4+
import volatile
5+
6+
from ..pep621 import Pep621Reader
7+
8+
9+
class Pep621ReaderTest(unittest.TestCase):
10+
def test_simplest(self) -> None:
11+
with volatile.dir() as d:
12+
dp = Path(d)
13+
(dp / "pyproject.toml").write_text(
14+
"""\
15+
[project]
16+
name = "Name"
17+
"""
18+
)
19+
20+
r = Pep621Reader(dp)
21+
md = r.get_pep621_metadata()
22+
self.assertEqual("Name", md.name)
23+
24+
def test_normal(self) -> None:
25+
with volatile.dir() as d:
26+
dp = Path(d)
27+
(dp / "pyproject.toml").write_text(
28+
"""\
29+
[project]
30+
name = "foo"
31+
dependencies = ["abc", "def"]
32+
license = {text = "MIT"}
33+
34+
[project.urls]
35+
Foo = "https://"
36+
"""
37+
)
38+
(dp / "foo").mkdir()
39+
(dp / "foo" / "tests").mkdir()
40+
(dp / "foo" / "__init__.py").write_text("")
41+
(dp / "foo" / "tests" / "__init__.py").write_text("")
42+
43+
r = Pep621Reader(dp)
44+
md = r.get_pep621_metadata()
45+
self.assertEqual("foo", md.name)
46+
self.assertEqual(
47+
{
48+
"metadata_version": "2.1",
49+
"name": "foo",
50+
"license": "MIT",
51+
"packages": ["foo", "foo.tests"],
52+
"packages_dict": {"foo": "foo", "foo.tests": "foo/tests"},
53+
"requires_dist": ["abc", "def"],
54+
"project_urls": {"Foo": "https://"},
55+
},
56+
md.asdict(),
57+
)

0 commit comments

Comments
 (0)