Skip to content

Commit 9bbb7cc

Browse files
authored
Merge pull request #7 from python-packaging/homepage-project-urls
Parse metadata fields from sdist artifacts
2 parents 5815c7a + e69ee20 commit 9bbb7cc

File tree

4 files changed

+97
-16
lines changed

4 files changed

+97
-16
lines changed

metadata_please/sdist.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,23 @@ def from_zip_sdist(zf: ZipFile) -> bytes:
3030
def basic_metadata_from_zip_sdist(zf: ZipFile) -> BasicMetadata:
3131
requires = [f for f in zf.namelist() if f.endswith("/requires.txt")]
3232
requires.sort(key=len)
33-
if not requires:
34-
return BasicMetadata((), frozenset(), "-")
33+
if requires:
34+
requires_data = zf.read(requires[0])
35+
assert requires_data is not None
36+
else:
37+
requires_data = b""
3538

36-
data = zf.read(requires[0])
37-
assert data is not None
38-
return BasicMetadata.from_sdist_pkg_info_and_requires(b"", data)
39+
# Find the PKG-INFO file with the shortest path. This is to avoid picking up
40+
# a PKG-INFO file from a nested test directory.
41+
pkg_info = sorted(
42+
(f for f in zf.namelist() if f == "PKG-INFO" or f.endswith("/PKG-INFO")),
43+
key=len,
44+
)[0]
45+
46+
pkg_info_data = zf.read(pkg_info)
47+
assert pkg_info_data is not None
48+
49+
return BasicMetadata.from_sdist_pkg_info_and_requires(pkg_info_data, requires_data)
3950

4051

4152
def from_tar_sdist(tf: TarFile) -> bytes:
@@ -58,17 +69,31 @@ def from_tar_sdist(tf: TarFile) -> bytes:
5869
buf.append(f"Requires-Dist: {req}\n")
5970
for extra in sorted(extras):
6071
buf.append(f"Provides-Extra: {extra}\n")
72+
6173
return ("".join(buf)).encode("utf-8")
6274

6375

6476
def basic_metadata_from_tar_sdist(tf: TarFile) -> BasicMetadata:
6577
# XXX Why do ZipFile and TarFile not have a common interface ?!
6678
requires = [f for f in tf.getnames() if f.endswith("/requires.txt")]
6779
requires.sort(key=len)
68-
if not requires:
69-
return BasicMetadata((), frozenset())
70-
71-
fo = tf.extractfile(requires[0])
72-
assert fo is not None
73-
74-
return BasicMetadata.from_sdist_pkg_info_and_requires(b"", fo.read())
80+
if requires:
81+
requires_fo = tf.extractfile(requires[0])
82+
assert requires_fo is not None
83+
requires_data = requires_fo.read()
84+
else:
85+
requires_data = b""
86+
87+
# Find the PKG-INFO file with the shortest path. This is to avoid picking up
88+
# a PKG-INFO file from a nested test directory.
89+
pkg_info = sorted(
90+
(f for f in tf.getnames() if f == "PKG-INFO" or f.endswith("/PKG-INFO")),
91+
key=len,
92+
)[0]
93+
94+
pkg_info_fo = tf.extractfile(pkg_info)
95+
assert pkg_info_fo is not None
96+
97+
return BasicMetadata.from_sdist_pkg_info_and_requires(
98+
pkg_info_fo.read(), requires_data
99+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
METADATA_CONTENTS = b"""\
2+
Requires-Dist: foo
3+
Version: 1.2.58
4+
Summary: Some Summary
5+
Home-page: http://example.com
6+
Author: Chicken
7+
Author-email: [email protected]
8+
Keywords: farm,animals
9+
Requires-Python: >=3.6
10+
Description-Content-Type: text/markdown
11+
12+
# Foo
13+
14+
A very important package.
15+
"""

metadata_please/tests/sdist.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
)
99
from ._tar import MemoryTarFile
1010
from ._zip import MemoryZipFile
11+
from .metadata_contents import METADATA_CONTENTS
1112

1213

1314
class ZipSdistTest(unittest.TestCase):
1415
def test_requires_as_expected(self) -> None:
1516
z = MemoryZipFile(
1617
{
1718
"foo/__init__.py": b"",
19+
"foo.egg-info/PKG-INFO": b"\n",
1820
"foo.egg-info/requires.txt": b"""\
1921
a
2022
[e]
@@ -36,6 +38,7 @@ def test_basic_metadata(self) -> None:
3638
z = MemoryZipFile(
3739
{
3840
"foo/__init__.py": b"",
41+
"foo.egg-info/PKG-INFO": b"\n",
3942
"foo.egg-info/requires.txt": b"""\
4043
a
4144
[e]
@@ -68,6 +71,7 @@ def test_basic_metadata_absl_py_09(self) -> None:
6871
z = MemoryZipFile(
6972
{
7073
"foo/__init__.py": b"",
74+
"foo.egg-info/PKG-INFO": b"\n",
7175
"foo.egg-info/requires.txt": b"""\
7276
six
7377
@@ -90,11 +94,32 @@ def test_basic_metadata_absl_py_09(self) -> None:
9094
)
9195
self.assertEqual({"test"}, bm.provides_extra)
9296

97+
def test_basic_metadata_fields(self) -> None:
98+
"""
99+
Modern setuptools will drop a PKG-INFO file in a sdist that is very similar to the METADATA file in a wheel.
100+
"""
101+
z = MemoryZipFile(
102+
{
103+
"foo/__init__.py": b"",
104+
"PKG-INFO": METADATA_CONTENTS,
105+
}
106+
)
107+
bm = basic_metadata_from_zip_sdist(z) # type: ignore
108+
self.assertEqual(["foo"], bm.reqs)
109+
self.assertEqual("1.2.58", bm.version)
110+
self.assertEqual("Some Summary", bm.summary)
111+
self.assertEqual("http://example.com", bm.url)
112+
self.assertEqual("Chicken", bm.author)
113+
self.assertEqual("[email protected]", bm.author_email)
114+
self.assertEqual("farm,animals", bm.keywords)
115+
self.assertEqual("text/markdown", bm.long_description_content_type)
116+
self.assertEqual("# Foo\n\nA very important package.\n", bm.description)
117+
93118

94119
class TarSdistTest(unittest.TestCase):
95120
def test_requires_as_expected(self) -> None:
96121
t = MemoryTarFile(
97-
["foo.egg-info/requires.txt", "foo/__init__.py"],
122+
["foo.egg-info/PKG-INFO", "foo.egg-info/requires.txt", "foo/__init__.py"],
98123
read_value=b"""\
99124
a
100125
[e]
@@ -113,7 +138,7 @@ def test_requires_as_expected(self) -> None:
113138

114139
def test_basic_metadata(self) -> None:
115140
t = MemoryTarFile(
116-
["foo.egg-info/requires.txt", "foo/__init__.py"],
141+
["foo.egg-info/PKG-INFO", "foo.egg-info/requires.txt", "foo/__init__.py"],
117142
read_value=b"""\
118143
a
119144
[e]
@@ -126,3 +151,18 @@ def test_basic_metadata(self) -> None:
126151
bm.reqs,
127152
)
128153
self.assertEqual({"e"}, bm.provides_extra)
154+
155+
def test_metadata_fields_from_tar_sdist(self) -> None:
156+
t = MemoryTarFile(
157+
["PKG-INFO", "foo/__init__.py"],
158+
read_value=METADATA_CONTENTS,
159+
)
160+
bm = basic_metadata_from_tar_sdist(t) # type: ignore
161+
self.assertEqual("1.2.58", bm.version)
162+
self.assertEqual("Some Summary", bm.summary)
163+
self.assertEqual("http://example.com", bm.url)
164+
self.assertEqual("Chicken", bm.author)
165+
self.assertEqual("[email protected]", bm.author_email)
166+
self.assertEqual("farm,animals", bm.keywords)
167+
self.assertEqual("text/markdown", bm.long_description_content_type)
168+
self.assertEqual("# Foo\n\nA very important package.\n", bm.description)

metadata_please/tests/wheel.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from ..wheel import basic_metadata_from_wheel, from_wheel, InvalidWheel
44
from ._zip import MemoryZipFile
5+
from .metadata_contents import METADATA_CONTENTS
56

67

78
class WheelTest(unittest.TestCase):
@@ -58,7 +59,7 @@ def test_basic_metadata(self) -> None:
5859
def test_basic_metadata_more_fields(self) -> None:
5960
z = MemoryZipFile(
6061
{
61-
"foo.dist-info/METADATA": b"Requires-Dist: foo\nVersion: 1.2.58\nSummary: Some Summary\nHome-page: http://example.com\nAuthor: Chicken\nAuthor-email: [email protected]\nKeywords: farm,animals\nRequires-Python: >=3.6\nDescription-Content-Type: text/markdown",
62+
"foo.dist-info/METADATA": METADATA_CONTENTS,
6263
"foo/__init__.py": b"",
6364
}
6465
)
@@ -71,4 +72,4 @@ def test_basic_metadata_more_fields(self) -> None:
7172
self.assertEqual("[email protected]", bm.author_email)
7273
self.assertEqual("farm,animals", bm.keywords)
7374
self.assertEqual("text/markdown", bm.long_description_content_type)
74-
self.assertEqual(None, bm.description)
75+
self.assertEqual("# Foo\n\nA very important package.\n", bm.description)

0 commit comments

Comments
 (0)