diff --git a/tests/helpers.py b/tests/helpers.py index da28a336..b1ea8068 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -13,8 +13,12 @@ # limitations under the License. """Test functions useful across twine's tests.""" +import io import os import pathlib +import tarfile +import textwrap +import zipfile TESTS_DIR = pathlib.Path(__file__).parent FIXTURES_DIR = os.path.join(TESTS_DIR, "fixtures") @@ -22,3 +26,28 @@ WHEEL_FIXTURE = os.path.join(FIXTURES_DIR, "twine-1.5.0-py2.py3-none-any.whl") NEW_SDIST_FIXTURE = os.path.join(FIXTURES_DIR, "twine-1.6.5.tar.gz") NEW_WHEEL_FIXTURE = os.path.join(FIXTURES_DIR, "twine-1.6.5-py2.py3-none-any.whl") + + +def build_archive(path, name, archive_format, files): + filepath = path / f"{name}.{archive_format}" + + if archive_format == "tar.gz": + with tarfile.open(filepath, "x:gz") as archive: + for mname, content in files.items(): + if isinstance(content, tarfile.TarInfo): + content.name = mname + archive.addfile(content) + else: + data = textwrap.dedent(content).encode("utf8") + member = tarfile.TarInfo(mname) + member.size = len(data) + archive.addfile(member, io.BytesIO(data)) + return filepath + + if archive_format == "zip": + with zipfile.ZipFile(filepath, mode="w") as archive: + for mname, content in files.items(): + archive.writestr(mname, textwrap.dedent(content)) + return filepath + + raise ValueError(format) diff --git a/tests/test_check.py b/tests/test_check.py index ca62d2c1..74e0b1ce 100644 --- a/tests/test_check.py +++ b/tests/test_check.py @@ -12,9 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging -import textwrap -import build import pretend import pytest @@ -50,45 +48,30 @@ def test_fails_no_distributions(caplog): ] -def build_package(src_path, project_files, distribution="sdist"): - """ - Build a source distribution similar to `python3 -m build --sdist`. - - Returns the absolute path of the built distribution. - """ - project_files = { - "pyproject.toml": ( - """ - [build-system] - requires = ["setuptools"] - build-backend = "setuptools.build_meta" - """ - ), - **project_files, - } - - for filename, content in project_files.items(): - (src_path / filename).write_text(textwrap.dedent(content)) - - builder = build.ProjectBuilder(src_path) - return builder.build(distribution, str(src_path / "dist")) +def build_sdist_with_metadata(path, metadata): + name = "test" + version = "1.2.3" + sdist = helpers.build_archive( + path, + f"{name}-{version}", + "tar.gz", + { + f"{name}-{version}/README": "README", + f"{name}-{version}/PKG-INFO": metadata, + }, + ) + return str(sdist) -@pytest.mark.parametrize("distribution", ["sdist", "wheel"]) @pytest.mark.parametrize("strict", [False, True]) -def test_warns_missing_description(distribution, strict, tmp_path, capsys, caplog): - sdist = build_package( +def test_warns_missing_description(strict, tmp_path, capsys, caplog): + sdist = build_sdist_with_metadata( tmp_path, - { - "setup.cfg": ( - """ - [metadata] - name = test-package - version = 0.0.1 - """ - ), - }, - distribution=distribution, + """\ + Metadata-Version: 2.1 + Name: test + Version: 1.2.3 + """, ) assert check.check([sdist], strict=strict) is strict @@ -111,54 +94,19 @@ def test_warns_missing_description(distribution, strict, tmp_path, capsys, caplo ] -def test_warns_missing_file(tmp_path, capsys, caplog): - sdist = build_package( +def test_fails_rst_syntax_error(tmp_path, capsys, caplog): + sdist = build_sdist_with_metadata( tmp_path, - { - "setup.cfg": ( - """ - [metadata] - name = test-package - version = 0.0.1 - long_description = file:README.rst - long_description_content_type = text/x-rst - """ - ), - }, - ) + """\ + Metadata-Version: 2.1 + Name: test-package + Version: 1.2.3 + Description-Content-Type: text/x-rst - assert not check.check([sdist]) - assert capsys.readouterr().out == f"Checking {sdist}: PASSED with warnings\n" + ============ - assert caplog.record_tuples == [ - ( - "twine.commands.check", - logging.WARNING, - "`long_description` missing.", - ), - ] - - -def test_fails_rst_syntax_error(tmp_path, capsys, caplog): - sdist = build_package( - tmp_path, - { - "setup.cfg": ( - """ - [metadata] - name = test-package - version = 0.0.1 - long_description = file:README.rst - long_description_content_type = text/x-rst - """ - ), - "README.rst": ( - """ - ============ - """ - ), - }, + """, ) assert check.check([sdist]) @@ -177,25 +125,17 @@ def test_fails_rst_syntax_error(tmp_path, capsys, caplog): def test_fails_rst_no_content(tmp_path, capsys, caplog): - sdist = build_package( + sdist = build_sdist_with_metadata( tmp_path, - { - "setup.cfg": ( - """ - [metadata] - name = test-package - version = 0.0.1 - long_description = file:README.rst - long_description_content_type = text/x-rst - """ - ), - "README.rst": ( - """ - test-package - ============ - """ - ), - }, + """\ + Metadata-Version: 2.1 + Name: test-package + Version: 1.2.3 + Description-Content-Type: text/x-rst + + test-package + ============ + """, ) assert check.check([sdist]) @@ -214,27 +154,19 @@ def test_fails_rst_no_content(tmp_path, capsys, caplog): def test_passes_rst_description(tmp_path, capsys, caplog): - sdist = build_package( + sdist = build_sdist_with_metadata( tmp_path, - { - "setup.cfg": ( - """ - [metadata] - name = test-package - version = 0.0.1 - long_description = file:README.rst - long_description_content_type = text/x-rst - """ - ), - "README.rst": ( - """ - test-package - ============ - - A test package. - """ - ), - }, + """\ + Metadata-Version: 2.1 + Name: test-package + Version: 1.2.3 + Description-Content-Type: text/x-rst + + test-package + ============ + + A test package. + """, ) assert not check.check([sdist]) @@ -246,26 +178,18 @@ def test_passes_rst_description(tmp_path, capsys, caplog): @pytest.mark.parametrize("content_type", ["text/markdown", "text/plain"]) def test_passes_markdown_description(content_type, tmp_path, capsys, caplog): - sdist = build_package( + sdist = build_sdist_with_metadata( tmp_path, - { - "setup.cfg": ( - f""" - [metadata] - name = test-package - version = 0.0.1 - long_description = file:README.md - long_description_content_type = {content_type} - """ - ), - "README.md": ( - """ - # test-package - - A test package. - """ - ), - }, + f"""\ + Metadata-Version: 2.1 + Name: test-package + Version: 1.2.3 + Description-Content-Type: {content_type} + + # test-package + + A test package. + """, ) assert not check.check([sdist]) diff --git a/tests/test_sdist.py b/tests/test_sdist.py index eb50b979..a619dfef 100644 --- a/tests/test_sdist.py +++ b/tests/test_sdist.py @@ -1,9 +1,6 @@ -import io import os import pathlib import tarfile -import textwrap -import zipfile import pytest @@ -11,6 +8,7 @@ from twine import sdist from .helpers import TESTS_DIR +from .helpers import build_archive @pytest.fixture( @@ -29,31 +27,6 @@ def archive_format(request): return request.param -def build_archive(path, name, archive_format, files): - filepath = path / f"{name}.{archive_format}" - - if archive_format == "tar.gz": - with tarfile.open(filepath, "x:gz") as archive: - for mname, content in files.items(): - if isinstance(content, tarfile.TarInfo): - content.name = mname - archive.addfile(content) - else: - data = textwrap.dedent(content).encode("utf8") - member = tarfile.TarInfo(mname) - member.size = len(data) - archive.addfile(member, io.BytesIO(data)) - return str(filepath) - - if archive_format == "zip": - with zipfile.ZipFile(filepath, mode="w") as archive: - for mname, content in files.items(): - archive.writestr(mname, textwrap.dedent(content)) - return str(filepath) - - raise ValueError(format) - - def test_read_example(example_sdist): """Parse metadata from a valid sdist file.""" metadata = example_sdist.read() @@ -78,7 +51,7 @@ def test_formar_not_supported(): def test_read(archive_format, tmp_path): """Read PKG-INFO from a valid sdist.""" - filename = build_archive( + filepath = build_archive( tmp_path, "test-1.2.3", archive_format, @@ -92,7 +65,7 @@ def test_read(archive_format, tmp_path): }, ) - metadata = sdist.SDist(filename).read() + metadata = sdist.SDist(str(filepath)).read() assert b"Metadata-Version: 1.1" in metadata assert b"Name: test" in metadata assert b"Version: 1.2.3" in metadata @@ -100,7 +73,7 @@ def test_read(archive_format, tmp_path): def test_missing_pkg_info(archive_format, tmp_path): """Raise an exception when sdist does not contain PKG-INFO.""" - filename = build_archive( + filepath = build_archive( tmp_path, "test-1.2.3", archive_format, @@ -110,12 +83,12 @@ def test_missing_pkg_info(archive_format, tmp_path): ) with pytest.raises(exceptions.InvalidDistribution, match="No PKG-INFO in archive"): - sdist.SDist(filename).read() + sdist.SDist(str(filepath)).read() def test_invalid_pkg_info(archive_format, tmp_path): """Raise an exception when PKG-INFO does not contain ``Metadata-Version``.""" - filename = build_archive( + filepath = build_archive( tmp_path, "test-1.2.3", archive_format, @@ -129,12 +102,12 @@ def test_invalid_pkg_info(archive_format, tmp_path): ) with pytest.raises(exceptions.InvalidDistribution, match="No PKG-INFO in archive"): - sdist.SDist(filename).read() + sdist.SDist(str(filepath)).read() def test_pkg_info_directory(archive_format, tmp_path): """Raise an exception when PKG-INFO is a directory.""" - filename = build_archive( + filepath = build_archive( tmp_path, "test-1.2.3", archive_format, @@ -149,7 +122,7 @@ def test_pkg_info_directory(archive_format, tmp_path): ) with pytest.raises(exceptions.InvalidDistribution, match="No PKG-INFO in archive"): - sdist.SDist(filename).read() + sdist.SDist(str(filepath)).read() def test_pkg_info_not_regular_file(tmp_path): @@ -158,7 +131,7 @@ def test_pkg_info_not_regular_file(tmp_path): link.type = tarfile.LNKTYPE link.linkname = "README" - filename = build_archive( + filepath = build_archive( tmp_path, "test-1.2.3", "tar.gz", @@ -169,12 +142,12 @@ def test_pkg_info_not_regular_file(tmp_path): ) with pytest.raises(exceptions.InvalidDistribution, match="PKG-INFO is not a reg"): - sdist.SDist(filename).read() + sdist.SDist(str(filepath)).read() def test_multiple_top_level(archive_format, tmp_path): """Raise an exception when there are too many top-level members.""" - filename = build_archive( + filepath = build_archive( tmp_path, "test-1.2.3", archive_format, @@ -190,7 +163,7 @@ def test_multiple_top_level(archive_format, tmp_path): ) with pytest.raises(exceptions.InvalidDistribution, match="Too many top-level"): - sdist.SDist(filename).read() + sdist.SDist(str(filepath)).read() def test_py_version(example_sdist): diff --git a/tox.ini b/tox.ini index e5c71aab..bf36c319 100644 --- a/tox.ini +++ b/tox.ini @@ -8,12 +8,7 @@ deps = pretend pytest pytest-socket - build coverage - # Needed on 3.12 and newer due to setuptools not being pre-installed - # in fresh venvs. - # See: https://github.com/python/cpython/issues/95299 - setuptools passenv = PYTEST_ADDOPTS setenv =