⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.144
Server IP:
157.245.143.252
Server:
Linux www 6.11.0-9-generic #9-Ubuntu SMP PREEMPT_DYNAMIC Mon Oct 14 13:19:59 UTC 2024 x86_64
Server Software:
nginx/1.26.0
PHP Version:
8.3.11
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
lib
/
python3
/
dist-packages
/
setuptools
/
tests
/
View File Name :
test_core_metadata.py
import functools import importlib import io from email import message_from_string import pytest from packaging.metadata import Metadata from setuptools import _reqs, sic from setuptools._core_metadata import rfc822_escape, rfc822_unescape from setuptools.command.egg_info import egg_info, write_requirements from setuptools.dist import Distribution EXAMPLE_BASE_INFO = dict( name="package", version="0.0.1", author="Foo Bar", author_email="foo@bar.net", long_description="Long\ndescription", description="Short description", keywords=["one", "two"], ) @pytest.mark.parametrize( 'content, result', ( pytest.param( "Just a single line", None, id="single_line", ), pytest.param( "Multiline\nText\nwithout\nextra indents\n", None, id="multiline", ), pytest.param( "Multiline\n With\n\nadditional\n indentation", None, id="multiline_with_indentation", ), pytest.param( " Leading whitespace", "Leading whitespace", id="remove_leading_whitespace", ), pytest.param( " Leading whitespace\nIn\n Multiline comment", "Leading whitespace\nIn\n Multiline comment", id="remove_leading_whitespace_multiline", ), ), ) def test_rfc822_unescape(content, result): assert (result or content) == rfc822_unescape(rfc822_escape(content)) def __read_test_cases(): base = EXAMPLE_BASE_INFO params = functools.partial(dict, base) return [ ('Metadata version 1.0', params()), ( 'Metadata Version 1.0: Short long description', params( long_description='Short long description', ), ), ( 'Metadata version 1.1: Classifiers', params( classifiers=[ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7', 'License :: OSI Approved :: MIT License', ], ), ), ( 'Metadata version 1.1: Download URL', params( download_url='https://example.com', ), ), ( 'Metadata Version 1.2: Requires-Python', params( python_requires='>=3.7', ), ), pytest.param( 'Metadata Version 1.2: Project-Url', params(project_urls=dict(Foo='https://example.bar')), marks=pytest.mark.xfail( reason="Issue #1578: project_urls not read", ), ), ( 'Metadata Version 2.1: Long Description Content Type', params( long_description_content_type='text/x-rst; charset=UTF-8', ), ), ( 'License', params( license='MIT', ), ), ( 'License multiline', params( license='This is a long license \nover multiple lines', ), ), pytest.param( 'Metadata Version 2.1: Provides Extra', params(provides_extras=['foo', 'bar']), marks=pytest.mark.xfail(reason="provides_extras not read"), ), ( 'Missing author', dict( name='foo', version='1.0.0', author_email='snorri@sturluson.name', ), ), ( 'Missing author e-mail', dict( name='foo', version='1.0.0', author='Snorri Sturluson', ), ), ( 'Missing author and e-mail', dict( name='foo', version='1.0.0', ), ), ( 'Bypass normalized version', dict( name='foo', version=sic('1.0.0a'), ), ), ] @pytest.mark.parametrize('name,attrs', __read_test_cases()) def test_read_metadata(name, attrs): dist = Distribution(attrs) metadata_out = dist.metadata dist_class = metadata_out.__class__ # Write to PKG_INFO and then load into a new metadata object PKG_INFO = io.StringIO() metadata_out.write_pkg_file(PKG_INFO) PKG_INFO.seek(0) pkg_info = PKG_INFO.read() assert _valid_metadata(pkg_info) PKG_INFO.seek(0) metadata_in = dist_class() metadata_in.read_pkg_file(PKG_INFO) tested_attrs = [ ('name', dist_class.get_name), ('version', dist_class.get_version), ('author', dist_class.get_contact), ('author_email', dist_class.get_contact_email), ('metadata_version', dist_class.get_metadata_version), ('provides', dist_class.get_provides), ('description', dist_class.get_description), ('long_description', dist_class.get_long_description), ('download_url', dist_class.get_download_url), ('keywords', dist_class.get_keywords), ('platforms', dist_class.get_platforms), ('obsoletes', dist_class.get_obsoletes), ('requires', dist_class.get_requires), ('classifiers', dist_class.get_classifiers), ('project_urls', lambda s: getattr(s, 'project_urls', {})), ('provides_extras', lambda s: getattr(s, 'provides_extras', {})), ] for attr, getter in tested_attrs: assert getter(metadata_in) == getter(metadata_out) def __maintainer_test_cases(): attrs = {"name": "package", "version": "1.0", "description": "xxx"} def merge_dicts(d1, d2): d1 = d1.copy() d1.update(d2) return d1 return [ ('No author, no maintainer', attrs.copy()), ( 'Author (no e-mail), no maintainer', merge_dicts(attrs, {'author': 'Author Name'}), ), ( 'Author (e-mail), no maintainer', merge_dicts( attrs, {'author': 'Author Name', 'author_email': 'author@name.com'} ), ), ( 'No author, maintainer (no e-mail)', merge_dicts(attrs, {'maintainer': 'Maintainer Name'}), ), ( 'No author, maintainer (e-mail)', merge_dicts( attrs, { 'maintainer': 'Maintainer Name', 'maintainer_email': 'maintainer@name.com', }, ), ), ( 'Author (no e-mail), Maintainer (no-email)', merge_dicts( attrs, {'author': 'Author Name', 'maintainer': 'Maintainer Name'} ), ), ( 'Author (e-mail), Maintainer (e-mail)', merge_dicts( attrs, { 'author': 'Author Name', 'author_email': 'author@name.com', 'maintainer': 'Maintainer Name', 'maintainer_email': 'maintainer@name.com', }, ), ), ( 'No author (e-mail), no maintainer (e-mail)', merge_dicts( attrs, { 'author_email': 'author@name.com', 'maintainer_email': 'maintainer@name.com', }, ), ), ('Author unicode', merge_dicts(attrs, {'author': '鉄沢寛'})), ('Maintainer unicode', merge_dicts(attrs, {'maintainer': 'Jan Łukasiewicz'})), ] @pytest.mark.parametrize('name,attrs', __maintainer_test_cases()) def test_maintainer_author(name, attrs, tmpdir): tested_keys = { 'author': 'Author', 'author_email': 'Author-email', 'maintainer': 'Maintainer', 'maintainer_email': 'Maintainer-email', } # Generate a PKG-INFO file dist = Distribution(attrs) fn = tmpdir.mkdir('pkg_info') fn_s = str(fn) dist.metadata.write_pkg_info(fn_s) with open(str(fn.join('PKG-INFO')), 'r', encoding='utf-8') as f: pkg_info = f.read() assert _valid_metadata(pkg_info) # Drop blank lines and strip lines from default description raw_pkg_lines = pkg_info.splitlines() pkg_lines = list(filter(None, raw_pkg_lines[:-2])) pkg_lines_set = set(pkg_lines) # Duplicate lines should not be generated assert len(pkg_lines) == len(pkg_lines_set) for fkey, dkey in tested_keys.items(): val = attrs.get(dkey, None) if val is None: for line in pkg_lines: assert not line.startswith(fkey + ':') else: line = '%s: %s' % (fkey, val) assert line in pkg_lines_set def test_parity_with_metadata_from_pypa_wheel(tmp_path): attrs = dict( **EXAMPLE_BASE_INFO, # Example with complex requirement definition python_requires=">=3.8", install_requires=""" packaging==23.2 ordered-set==3.1.1 more-itertools==8.8.0; extra == "other" jaraco.text==3.7.0 importlib-resources==5.10.2; python_version<"3.8" importlib-metadata==6.0.0 ; python_version<"3.8" colorama>=0.4.4; sys_platform == "win32" """, extras_require={ "testing": """ pytest >= 6 pytest-checkdocs >= 2.4 tomli ; \\ # Using stdlib when possible python_version < "3.11" ini2toml[lite]>=0.9 """, "other": [], }, ) # Generate a PKG-INFO file using setuptools dist = Distribution(attrs) with io.StringIO() as fp: dist.metadata.write_pkg_file(fp) pkg_info = fp.getvalue() assert _valid_metadata(pkg_info) # Ensure Requires-Dist is present expected = [ 'Metadata-Version:', 'Requires-Python: >=3.8', 'Provides-Extra: other', 'Provides-Extra: testing', 'Requires-Dist: tomli; python_version < "3.11" and extra == "testing"', 'Requires-Dist: more-itertools==8.8.0; extra == "other"', 'Requires-Dist: ini2toml[lite]>=0.9; extra == "testing"', ] for line in expected: assert line in pkg_info # Generate a METADATA file using pypa/wheel for comparison wheel_metadata = importlib.import_module("wheel.metadata") pkginfo_to_metadata = getattr(wheel_metadata, "pkginfo_to_metadata", None) if pkginfo_to_metadata is None: pytest.xfail( "wheel.metadata.pkginfo_to_metadata is undefined, " "(this is likely to be caused by API changes in pypa/wheel" ) # Generate an simplified "egg-info" dir for pypa/wheel to convert egg_info_dir = tmp_path / "pkg.egg-info" egg_info_dir.mkdir(parents=True) (egg_info_dir / "PKG-INFO").write_text(pkg_info, encoding="utf-8") write_requirements(egg_info(dist), egg_info_dir, egg_info_dir / "requires.txt") # Get pypa/wheel generated METADATA but normalize requirements formatting metadata_msg = pkginfo_to_metadata(egg_info_dir, egg_info_dir / "PKG-INFO") metadata_deps = set(_reqs.parse(metadata_msg.get_all("Requires-Dist"))) metadata_extras = set(metadata_msg.get_all("Provides-Extra")) del metadata_msg["Requires-Dist"] del metadata_msg["Provides-Extra"] pkg_info_msg = message_from_string(pkg_info) pkg_info_deps = set(_reqs.parse(pkg_info_msg.get_all("Requires-Dist"))) pkg_info_extras = set(pkg_info_msg.get_all("Provides-Extra")) del pkg_info_msg["Requires-Dist"] del pkg_info_msg["Provides-Extra"] # Compare setuptools PKG-INFO x pypa/wheel METADATA assert metadata_msg.as_string() == pkg_info_msg.as_string() assert metadata_deps == pkg_info_deps assert metadata_extras == pkg_info_extras def _valid_metadata(text: str) -> bool: metadata = Metadata.from_email(text, validate=True) # can raise exceptions return metadata is not None