|
1 | 1 | """Tests for PEP 658 metadata support.""" |
2 | 2 |
|
3 | 3 | import typing |
| 4 | +from io import BytesIO |
4 | 5 | from unittest.mock import Mock, patch |
| 6 | +from zipfile import ZipFile |
5 | 7 |
|
| 8 | +import pytest |
6 | 9 | from packaging.version import Version |
7 | 10 |
|
8 | | -from fromager.candidate import Candidate, get_metadata_for_wheel |
| 11 | +from fromager.candidate import ( |
| 12 | + Candidate, |
| 13 | + _wheel_metadata_path, |
| 14 | + get_metadata_for_wheel, |
| 15 | +) |
| 16 | +from fromager.pkgmetadata.pep376 import dist_info_name |
9 | 17 |
|
10 | 18 |
|
11 | 19 | class TestPEP658Support: |
@@ -191,3 +199,93 @@ def test_pep658_integration_with_resolver(self) -> None: |
191 | 199 | assert candidate_with_metadata.name == candidate_without_metadata.name |
192 | 200 | assert candidate_with_metadata.version == candidate_without_metadata.version |
193 | 201 | assert candidate_with_metadata.url == candidate_without_metadata.url |
| 202 | + |
| 203 | + |
| 204 | +class TestDistInfoName: |
| 205 | + """Test dist_info_name — single source of truth for dist-info directory names.""" |
| 206 | + |
| 207 | + def test_standard_wheel(self) -> None: |
| 208 | + assert ( |
| 209 | + dist_info_name("test_package-1.0.0-py3-none-any.whl") |
| 210 | + == "test_package-1.0.0.dist-info" |
| 211 | + ) |
| 212 | + |
| 213 | + def test_preserves_verbatim_casing(self) -> None: |
| 214 | + assert ( |
| 215 | + dist_info_name("MarkupSafe-2.1.0-cp311-cp311-linux_x86_64.whl") |
| 216 | + == "MarkupSafe-2.1.0.dist-info" |
| 217 | + ) |
| 218 | + |
| 219 | + def test_non_wheel_extension_raises(self) -> None: |
| 220 | + with pytest.raises(ValueError, match="Invalid wheel filename"): |
| 221 | + dist_info_name("pkg-1.0.tar.gz") |
| 222 | + |
| 223 | + def test_malformed_wheel_filename_raises(self) -> None: |
| 224 | + with pytest.raises(ValueError, match="Invalid wheel filename"): |
| 225 | + dist_info_name("pkg-1.0-bad.whl") |
| 226 | + |
| 227 | + |
| 228 | +class TestWheelMetadataPath: |
| 229 | + """Test _wheel_metadata_path — URL to METADATA zip path.""" |
| 230 | + |
| 231 | + def test_simple_wheel_url(self) -> None: |
| 232 | + url = "https://pkg.test/simple/test_package-1.0.0-py3-none-any.whl" |
| 233 | + assert _wheel_metadata_path(url) == "test_package-1.0.0.dist-info/METADATA" |
| 234 | + |
| 235 | + def test_preserves_original_casing(self) -> None: |
| 236 | + url = "https://pkg.test/simple/MarkupSafe-2.1.0-cp311-cp311-linux_x86_64.whl" |
| 237 | + assert _wheel_metadata_path(url) == "MarkupSafe-2.1.0.dist-info/METADATA" |
| 238 | + |
| 239 | + def test_url_with_path_segments(self) -> None: |
| 240 | + url = "https://pkg.test/packages/ab/cd/my_pkg-0.9-py3-none-any.whl" |
| 241 | + assert _wheel_metadata_path(url) == "my_pkg-0.9.dist-info/METADATA" |
| 242 | + |
| 243 | + def test_url_with_fragment(self) -> None: |
| 244 | + url = "https://pkg.test/simple/pkg-1.0-py3-none-any.whl#sha256=abc123" |
| 245 | + assert _wheel_metadata_path(url) == "pkg-1.0.dist-info/METADATA" |
| 246 | + |
| 247 | + @patch("fromager.candidate.session") |
| 248 | + def test_fallback_selects_correct_distinfo(self, mock_session: typing.Any) -> None: |
| 249 | + """Wheels with vendored dist-info directories must not confuse extraction.""" |
| 250 | + # Build a wheel zip with a vendored dist-info AND the real one |
| 251 | + buf = BytesIO() |
| 252 | + with ZipFile(buf, "w") as zf: |
| 253 | + zf.writestr( |
| 254 | + "vendored/six-1.16.0.dist-info/METADATA", |
| 255 | + "Metadata-Version: 2.1\nName: six\nVersion: 1.16.0\n", |
| 256 | + ) |
| 257 | + zf.writestr( |
| 258 | + "my_pkg-1.0.0.dist-info/METADATA", |
| 259 | + ( |
| 260 | + "Metadata-Version: 2.1\n" |
| 261 | + "Name: my-pkg\n" |
| 262 | + "Version: 1.0.0\n" |
| 263 | + "Summary: The real package\n" |
| 264 | + ), |
| 265 | + ) |
| 266 | + |
| 267 | + mock_response = Mock() |
| 268 | + mock_response.content = buf.getvalue() |
| 269 | + mock_session.get.return_value = mock_response |
| 270 | + |
| 271 | + wheel_url = "https://pkg.test/simple/my_pkg-1.0.0-py3-none-any.whl" |
| 272 | + metadata = get_metadata_for_wheel(wheel_url, metadata_url=None) |
| 273 | + |
| 274 | + assert metadata.name == "my-pkg" |
| 275 | + assert str(metadata.version) == "1.0.0" |
| 276 | + assert metadata.summary == "The real package" |
| 277 | + |
| 278 | + @patch("fromager.candidate.session") |
| 279 | + def test_fallback_missing_metadata_raises(self, mock_session: typing.Any) -> None: |
| 280 | + """A wheel without the expected dist-info/METADATA raises ValueError.""" |
| 281 | + buf = BytesIO() |
| 282 | + with ZipFile(buf, "w") as zf: |
| 283 | + zf.writestr("some_other_file.txt", "hello") |
| 284 | + |
| 285 | + mock_response = Mock() |
| 286 | + mock_response.content = buf.getvalue() |
| 287 | + mock_session.get.return_value = mock_response |
| 288 | + |
| 289 | + wheel_url = "https://pkg.test/simple/my_pkg-1.0.0-py3-none-any.whl" |
| 290 | + with pytest.raises(ValueError, match="Could not find"): |
| 291 | + get_metadata_for_wheel(wheel_url, metadata_url=None) |
0 commit comments