|
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( |
@@ -243,3 +246,82 @@ def test_maintainer_author(name, attrs, tmpdir): |
243 | 246 | else: |
244 | 247 | line = '%s: %s' % (fkey, val) |
245 | 248 | assert line in pkg_lines_set |
| 249 | + |
| 250 | + |
| 251 | +def test_parity_with_metadata_from_pypa_wheel(tmp_path): |
| 252 | + attrs = dict( |
| 253 | + **EXAMPLE_BASE_INFO, |
| 254 | + # Example with complex requirement definition |
| 255 | + python_requires=">=3.8", |
| 256 | + install_requires=""" |
| 257 | + packaging==23.0 |
| 258 | + ordered-set==3.1.1 |
| 259 | + more-itertools==8.8.0; extra == "other" |
| 260 | + jaraco.text==3.7.0 |
| 261 | + importlib-resources==5.10.2; python_version<"3.8" |
| 262 | + importlib-metadata==6.0.0 ; python_version<"3.8" |
| 263 | + colorama>=0.4.4; sys_platform == "win32" |
| 264 | + """, |
| 265 | + extras_require={ |
| 266 | + "testing": """ |
| 267 | + pytest >= 6 |
| 268 | + pytest-checkdocs >= 2.4 |
| 269 | + pytest-flake8 ; \\ |
| 270 | + # workaround for tholo/pytest-flake8#87 |
| 271 | + python_version < "3.12" |
| 272 | + ini2toml[lite]>=0.9 |
| 273 | + """, |
| 274 | + "other": [], |
| 275 | + } |
| 276 | + ) |
| 277 | + # Generate a PKG-INFO file using setuptools |
| 278 | + dist = Distribution(attrs) |
| 279 | + with io.StringIO() as fp: |
| 280 | + dist.metadata.write_pkg_file(fp) |
| 281 | + pkg_info = fp.getvalue() |
| 282 | + |
| 283 | + # Ensure Requires-Dist is present |
| 284 | + expected = [ |
| 285 | + 'Metadata-Version:', |
| 286 | + 'Requires-Python: >=3.8', |
| 287 | + 'Provides-Extra: other', |
| 288 | + 'Provides-Extra: testing', |
| 289 | + 'Requires-Dist: pytest-flake8; python_version < "3.12" and extra == "testing"', |
| 290 | + 'Requires-Dist: more-itertools==8.8.0; extra == "other"', |
| 291 | + 'Requires-Dist: ini2toml[lite]>=0.9; extra == "testing"', |
| 292 | + ] |
| 293 | + for line in expected: |
| 294 | + assert line in pkg_info |
| 295 | + |
| 296 | + # Generate a METADATA file using pypa/wheel for comparisson |
| 297 | + wheel_metadata = importlib.import_module("wheel.metadata") |
| 298 | + pkginfo_to_metadata = getattr(wheel_metadata, "pkginfo_to_metadata", None) |
| 299 | + |
| 300 | + if pkginfo_to_metadata is None: |
| 301 | + pytest.xfail( |
| 302 | + "wheel.metadata.pkginfo_to_metadata is undefined, " |
| 303 | + "(this is likely to be caused by API changes in pypa/wheel" |
| 304 | + ) |
| 305 | + |
| 306 | + # Generate an simplified "egg-info" dir for pypa/wheel to convert |
| 307 | + egg_info_dir = tmp_path / "pkg.egg-info" |
| 308 | + egg_info_dir.mkdir(parents=True) |
| 309 | + (egg_info_dir / "PKG-INFO").write_text(pkg_info, encoding="utf-8") |
| 310 | + write_requirements(egg_info(dist), egg_info_dir, egg_info_dir / "requires.txt") |
| 311 | + |
| 312 | + # Get pypa/wheel generated METADATA but normalize requirements formatting |
| 313 | + metadata_msg = pkginfo_to_metadata(egg_info_dir, egg_info_dir / "PKG-INFO") |
| 314 | + metadata_deps = set(_reqs.parse(metadata_msg.get_all("Requires-Dist"))) |
| 315 | + metadata_extras = set(metadata_msg.get_all("Provides-Extra")) |
| 316 | + del metadata_msg["Requires-Dist"] |
| 317 | + del metadata_msg["Provides-Extra"] |
| 318 | + pkg_info_msg = message_from_string(pkg_info) |
| 319 | + pkg_info_deps = set(_reqs.parse(pkg_info_msg.get_all("Requires-Dist"))) |
| 320 | + pkg_info_extras = set(pkg_info_msg.get_all("Provides-Extra")) |
| 321 | + del pkg_info_msg["Requires-Dist"] |
| 322 | + del pkg_info_msg["Provides-Extra"] |
| 323 | + |
| 324 | + # Compare setuptools PKG-INFO x pypa/wheel METADATA |
| 325 | + assert metadata_msg.as_string() == pkg_info_msg.as_string() |
| 326 | + assert metadata_deps == pkg_info_deps |
| 327 | + assert metadata_extras == pkg_info_extras |
0 commit comments