Skip to content

Commit

Permalink
Merge branch 'main' into 856-verbose-response
Browse files Browse the repository at this point in the history
  • Loading branch information
bhrutledge committed Jan 22, 2022
2 parents c800a21 + a60c565 commit a228795
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 34 deletions.
1 change: 1 addition & 0 deletions changelog/861.feature.rst
@@ -0,0 +1 @@
Show more helpful error message for invalid metadata.
1 change: 1 addition & 0 deletions setup.cfg
Expand Up @@ -40,6 +40,7 @@ install_requires=
readme_renderer >= 21.0
requests >= 2.20
requests-toolbelt >= 0.8.0, != 0.9.0
urllib3 >= 1.26.0
tqdm >= 4.14
importlib_metadata >= 3.6
keyring >= 15.1
Expand Down
39 changes: 31 additions & 8 deletions tests/test_package.py
Expand Up @@ -337,23 +337,46 @@ def test_fips_metadata_excludes_md5_and_blake2(monkeypatch):
assert "blake2_256_digest" not in mddict


def test_pkginfo_returns_no_metadata(monkeypatch):
@pytest.mark.parametrize(
"read_data, missing_fields",
[
pytest.param(
b"Metadata-Version: 2.3\nName: test-package\nVersion: 1.0.0\n",
"Name, Version",
id="unsupported Metadata-Version",
),
pytest.param(
b"Metadata-Version: 2.2\nName: UNKNOWN\nVersion: UNKNOWN\n",
"Name, Version",
id="missing Name and Version",
),
pytest.param(
b"Metadata-Version: 2.2\nName: UNKNOWN\nVersion: 1.0.0\n",
"Name",
id="missing Name",
),
pytest.param(
b"Metadata-Version: 2.2\nName: test-package\nVersion: UNKNOWN\n",
"Version",
id="missing Version",
),
],
)
def test_pkginfo_returns_no_metadata(read_data, missing_fields, monkeypatch):
"""Raise an exception when pkginfo can't interpret the metadata.
This could be caused by a version number or format it doesn't support yet.
"""

def EmptyDist(filename):
return pretend.stub(name=None, version=None)

monkeypatch.setattr(package_file, "DIST_TYPES", {"bdist_wheel": EmptyDist})
monkeypatch.setattr(package_file.wheel.Wheel, "read", lambda _: read_data)
filename = "tests/fixtures/twine-1.5.0-py2.py3-none-any.whl"

with pytest.raises(exceptions.InvalidDistribution) as err:
package_file.PackageFile.from_filename(filename, comment=None)

assert "Invalid distribution metadata" in err.value.args[0]
assert "1.0, 1.1, 1.2, 2.0, 2.1, and 2.2" in err.value.args[0]
assert (
f"Metadata is missing required fields: {missing_fields}." in err.value.args[0]
)
assert "1.0, 1.1, 1.2, 2.0, 2.1, 2.2" in err.value.args[0]


def test_malformed_from_file(monkeypatch):
Expand Down
19 changes: 8 additions & 11 deletions twine/cli.py
Expand Up @@ -14,23 +14,18 @@
import argparse
from typing import Any, List, Tuple

from importlib_metadata import entry_points
from importlib_metadata import version
import importlib_metadata
from packaging import requirements

import twine

args = argparse.Namespace()


def list_dependencies_and_versions() -> List[Tuple[str, str]]:
deps = (
"importlib_metadata",
"pkginfo",
"requests",
"requests-toolbelt",
"tqdm",
)
return [(dep, version(dep)) for dep in deps] # type: ignore[no-untyped-call] # python/importlib_metadata#288 # noqa: E501
requires = importlib_metadata.requires("twine") # type: ignore[no-untyped-call] # python/importlib_metadata#288 # noqa: E501
deps = [requirements.Requirement(r).name for r in requires]
return [(dep, importlib_metadata.version(dep)) for dep in deps] # type: ignore[no-untyped-call] # python/importlib_metadata#288 # noqa: E501


def dep_versions() -> str:
Expand All @@ -40,7 +35,9 @@ def dep_versions() -> str:


def dispatch(argv: List[str]) -> Any:
registered_commands = entry_points(group="twine.registered_commands")
registered_commands = importlib_metadata.entry_points(
group="twine.registered_commands"
)
parser = argparse.ArgumentParser(prog="twine")
parser.add_argument(
"--version",
Expand Down
20 changes: 13 additions & 7 deletions twine/package.py
Expand Up @@ -101,15 +101,21 @@ def from_filename(cls, filename: str, comment: Optional[str]) -> "PackageFile":
"Unknown distribution format: '%s'" % os.path.basename(filename)
)

# If pkginfo encounters a metadata version it doesn't support, it may
# give us back empty metadata. At the very least, we should have a name
# and version
if not (meta.name and meta.version):
# If pkginfo encounters a metadata version it doesn't support, it may give us
# back empty metadata. At the very least, we should have a name and version,
# which could also be empty if, for example, a MANIFEST.in doesn't include
# setup.cfg.
missing_fields = [
f.capitalize() for f in ["name", "version"] if not getattr(meta, f)
]
if missing_fields:
supported_metadata = list(pkginfo.distribution.HEADER_ATTRS)
raise exceptions.InvalidDistribution(
"Invalid distribution metadata. "
"This version of twine supports Metadata-Version "
f"{', '.join(supported_metadata[:-1])}, and {supported_metadata[-1]}"
"Metadata is missing required fields: "
f"{', '.join(missing_fields)}.\n"
"Make sure the distribution includes the files where those fields "
"are specified, and is using a supported Metadata-Version: "
f"{', '.join(supported_metadata)}."
)

py_version: Optional[str]
Expand Down
10 changes: 2 additions & 8 deletions twine/repository.py
Expand Up @@ -77,19 +77,13 @@ def __init__(

@staticmethod
def _make_adapter_with_retries() -> adapters.HTTPAdapter:
retry_kwargs = dict(
retry = urllib3.Retry(
allowed_methods=["GET"],
connect=5,
total=10,
status_forcelist=[500, 501, 502, 503],
)

try:
retry = urllib3.Retry(allowed_methods=["GET"], **retry_kwargs)
except TypeError: # pragma: no cover
# Avoiding DeprecationWarning starting in urllib3 1.26
# Remove when that's the mininum version
retry = urllib3.Retry(method_whitelist=["GET"], **retry_kwargs)

return adapters.HTTPAdapter(max_retries=retry)

@staticmethod
Expand Down

0 comments on commit a228795

Please sign in to comment.