|
1 | 1 | import functools
|
2 | 2 | import io
|
| 3 | +import importlib |
| 4 | +from email import message_from_string |
3 | 5 |
|
4 | 6 | import pytest
|
5 | 7 |
|
6 |
| -from setuptools import sic |
| 8 | +from setuptools import sic, _reqs |
7 | 9 | from setuptools.dist import Distribution
|
8 | 10 | from setuptools._core_metadata import rfc822_escape, rfc822_unescape
|
| 11 | +from setuptools.command.egg_info import egg_info, write_requirements |
9 | 12 |
|
10 | 13 |
|
11 | 14 | EXAMPLE_BASE_INFO = dict(
|
@@ -296,3 +299,82 @@ def test_maintainer_author(name, attrs, tmpdir):
|
296 | 299 | else:
|
297 | 300 | line = '%s: %s' % (fkey, val)
|
298 | 301 | assert line in pkg_lines_set
|
| 302 | + |
| 303 | + |
| 304 | +def test_parity_with_metadata_from_pypa_wheel(tmp_path): |
| 305 | + attrs = dict( |
| 306 | + **EXAMPLE_BASE_INFO, |
| 307 | + # Example with complex requirement definition |
| 308 | + python_requires=">=3.8", |
| 309 | + install_requires=""" |
| 310 | + packaging==23.0 |
| 311 | + ordered-set==3.1.1 |
| 312 | + more-itertools==8.8.0; extra == "other" |
| 313 | + jaraco.text==3.7.0 |
| 314 | + importlib-resources==5.10.2; python_version<"3.8" |
| 315 | + importlib-metadata==6.0.0 ; python_version<"3.8" |
| 316 | + colorama>=0.4.4; sys_platform == "win32" |
| 317 | + """, |
| 318 | + extras_require={ |
| 319 | + "testing": """ |
| 320 | + pytest >= 6 |
| 321 | + pytest-checkdocs >= 2.4 |
| 322 | + pytest-flake8 ; \\ |
| 323 | + # workaround for tholo/pytest-flake8#87 |
| 324 | + python_version < "3.12" |
| 325 | + ini2toml[lite]>=0.9 |
| 326 | + """, |
| 327 | + "other": [], |
| 328 | + } |
| 329 | + ) |
| 330 | + # Generate a PKG-INFO file using setuptools |
| 331 | + dist = Distribution(attrs) |
| 332 | + with io.StringIO() as fp: |
| 333 | + dist.metadata.write_pkg_file(fp) |
| 334 | + pkg_info = fp.getvalue() |
| 335 | + |
| 336 | + # Ensure Requires-Dist is present |
| 337 | + expected = [ |
| 338 | + 'Metadata-Version:', |
| 339 | + 'Requires-Python: >=3.8', |
| 340 | + 'Provides-Extra: other', |
| 341 | + 'Provides-Extra: testing', |
| 342 | + 'Requires-Dist: pytest-flake8; python_version < "3.12" and extra == "testing"', |
| 343 | + 'Requires-Dist: more-itertools==8.8.0; extra == "other"', |
| 344 | + 'Requires-Dist: ini2toml[lite]>=0.9; extra == "testing"', |
| 345 | + ] |
| 346 | + for line in expected: |
| 347 | + assert line in pkg_info |
| 348 | + |
| 349 | + # Generate a METADATA file using pypa/wheel for comparisson |
| 350 | + wheel_metadata = importlib.import_module("wheel.metadata") |
| 351 | + pkginfo_to_metadata = getattr(wheel_metadata, "pkginfo_to_metadata", None) |
| 352 | + |
| 353 | + if pkginfo_to_metadata is None: |
| 354 | + pytest.xfail( |
| 355 | + "wheel.metadata.pkginfo_to_metadata is undefined, " |
| 356 | + "(this is likely to be caused by API changes in pypa/wheel" |
| 357 | + ) |
| 358 | + |
| 359 | + # Generate an simplified "egg-info" dir for pypa/wheel to convert |
| 360 | + egg_info_dir = tmp_path / "pkg.egg-info" |
| 361 | + egg_info_dir.mkdir(parents=True) |
| 362 | + (egg_info_dir / "PKG-INFO").write_text(pkg_info, encoding="utf-8") |
| 363 | + write_requirements(egg_info(dist), egg_info_dir, egg_info_dir / "requires.txt") |
| 364 | + |
| 365 | + # Get pypa/wheel generated METADATA but normalize requirements formatting |
| 366 | + metadata_msg = pkginfo_to_metadata(egg_info_dir, egg_info_dir / "PKG-INFO") |
| 367 | + metadata_deps = set(_reqs.parse(metadata_msg.get_all("Requires-Dist"))) |
| 368 | + metadata_extras = set(metadata_msg.get_all("Provides-Extra")) |
| 369 | + del metadata_msg["Requires-Dist"] |
| 370 | + del metadata_msg["Provides-Extra"] |
| 371 | + pkg_info_msg = message_from_string(pkg_info) |
| 372 | + pkg_info_deps = set(_reqs.parse(pkg_info_msg.get_all("Requires-Dist"))) |
| 373 | + pkg_info_extras = set(pkg_info_msg.get_all("Provides-Extra")) |
| 374 | + del pkg_info_msg["Requires-Dist"] |
| 375 | + del pkg_info_msg["Provides-Extra"] |
| 376 | + |
| 377 | + # Compare setuptools PKG-INFO x pypa/wheel METADATA |
| 378 | + assert metadata_msg.as_string() == pkg_info_msg.as_string() |
| 379 | + assert metadata_deps == pkg_info_deps |
| 380 | + assert metadata_extras == pkg_info_extras |
0 commit comments