Repository: pypa/twine
Pull request #1028 (2023-11-22 23:03:52)

upload: warn about potential PGP deprecation
This is my (belated) follow-on to #1010: when the package URL *doesn't* look like PyPI or TestPyPI, we emit a separate warning message telling the user that `twine` *may* remove support for PGP signatures at some point in the future.

Like with the last changeset, I've added a testcase that ensures we render this error in the expected scenario.

See: #1009.


Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f9248c6..573c34f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,8 +15,8 @@ concurrency:
 env:
   FORCE_COLOR: "1"
   TOX_TESTENV_PASSENV: "FORCE_COLOR"
-  MIN_PYTHON_VERSION: "3.8"
-  DEFAULT_PYTHON_VERSION: "3.10"
+  MIN_PYTHON_VERSION: "3.7"
+  DEFAULT_PYTHON_VERSION: "3.9"
 
 permissions:
   contents: read
@@ -38,11 +38,10 @@ jobs:
     strategy:
       matrix:
         python-version:
+          - "3.7"
           - "3.8"
           - "3.9"
           - "3.10"
-          - "3.11"
-          - "3.12"
         platform:
           - ubuntu-latest
           - macos-latest
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 1a4677e..ef4b6f4 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,7 +1,5 @@
 doc8>=0.8.0
 furo>=2021.10.09
 readme-renderer>=17.4
-# Remove this upper bound when twine's minimum Python is 3.9+.
-# See: https://github.com/sphinx-doc/sphinx/issues/11767
-Sphinx>=6,<7.1
+Sphinx>=4.3.1
 sphinxcontrib-programoutput>=0.17
diff --git a/setup.cfg b/setup.cfg
index 86704c2..5196d55 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -27,15 +27,13 @@ classifiers =
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
     Programming Language :: Python :: 3.10
-    Programming Language :: Python :: 3.11
-    Programming Language :: Python :: 3.12
     Programming Language :: Python :: Implementation :: CPython
 
 [options]
 packages =
     twine
     twine.commands
-python_requires = >=3.8
+python_requires = >=3.7
 install_requires=
     pkginfo >= 1.8.1
     readme-renderer >= 35.0
diff --git a/tox.ini b/tox.ini
index c9c9ae0..813183c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
-minversion = 3.8
-envlist = lint,types,py{38,39,310,311,312},integration,docs
+minversion = 3.3
+envlist = lint,types,py{37,38,39,310},integration,docs
 isolated_build = True
 
 [testenv]
@@ -10,10 +10,6 @@ deps =
     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
 commands =
diff --git a/twine/commands/upload.py b/twine/commands/upload.py
index 75bf21a..186c591 100644
--- a/twine/commands/upload.py
+++ b/twine/commands/upload.py
@@ -124,17 +124,25 @@ def upload(upload_settings: settings.Settings, dists: List[str]) -> None:
         _make_package(filename, signatures, upload_settings) for filename in uploads
     ]
 
-    # Warn the user if they're trying to upload a PGP signature to PyPI
-    # or TestPyPI, which will (as of May 2023) ignore it.
-    # This check is currently limited to just those indices, since other
-    # indices may still support PGP signatures.
-    if any(p.gpg_signature for p in packages_to_upload) and repository_url.startswith(
-        (utils.DEFAULT_REPOSITORY, utils.TEST_REPOSITORY)
-    ):
-        logger.warning(
-            "One or more packages has an associated PGP signature; "
-            "these will be silently ignored by the index"
-        )
+    if any(p.gpg_signature for p in packages_to_upload):
+        if repository_url.startswith((utils.DEFAULT_REPOSITORY, utils.TEST_REPOSITORY)):
+            # Warn the user if they're trying to upload a PGP signature to PyPI
+            # or TestPyPI, which will (as of May 2023) ignore it.
+            # This warning is currently limited to just those indices, since other
+            # indices may still support PGP signatures.
+            logger.warning(
+                "One or more packages has an associated PGP signature; "
+                "these will be silently ignored by the index"
+            )
+        else:
+            # On other indices, warn the user that twine is considering
+            # removing PGP support outright.
+            logger.warning(
+                "One or more packages has an associated PGP signature; "
+                "a future version of twine may silently ignore these. "
+                "See https://github.com/pypa/twine/issues/1009 for more "
+                "information"
+            )
 
     repository = upload_settings.create_repository()
     uploaded_packages = []
diff --git a/twine/settings.py b/twine/settings.py
index 3f6b15f..4607c92 100644
--- a/twine/settings.py
+++ b/twine/settings.py
@@ -127,12 +127,14 @@ class Settings:
 
     @property
     def username(self) -> Optional[str]:
-        return self.auth.username
+        # Workaround for https://github.com/python/mypy/issues/5858
+        return cast(Optional[str], self.auth.username)
 
     @property
     def password(self) -> Optional[str]:
         with self._allow_noninteractive():
-            return self.auth.password
+            # Workaround for https://github.com/python/mypy/issues/5858
+            return cast(Optional[str], self.auth.password)
 
     def _allow_noninteractive(self) -> "contextlib.AbstractContextManager[None]":
         """Bypass NonInteractive error when client cert is present."""


Test patch:
diff --git a/tests/test_upload.py b/tests/test_upload.py
index c428306..894dec6 100644
--- a/tests/test_upload.py
+++ b/tests/test_upload.py
@@ -184,6 +184,42 @@ def test_success_with_pre_signed_distribution(upload_settings, stub_repository,
     )
 
 
+def test_warns_potential_pgp_removal_on_3p_index(
+    make_settings, stub_repository, caplog
+):
+    """Warn when a PGP signature is specified for upload to a third-party index."""
+    upload_settings = make_settings(
+        """
+        [pypi]
+        repository: https://example.com/not-a-real-index/
+        username:foo
+        password:bar
+        """
+    )
+    upload_settings.create_repository = lambda: stub_repository
+
+    # Upload a pre-signed distribution
+    result = upload.upload(
+        upload_settings, [helpers.WHEEL_FIXTURE, helpers.WHEEL_FIXTURE + ".asc"]
+    )
+    assert result is None
+
+    # The signature should be added via package.add_gpg_signature()
+    package = stub_repository.upload.calls[0].args[0]
+    assert package.gpg_signature == (
+        "twine-1.5.0-py2.py3-none-any.whl.asc",
+        b"signature",
+    )
+
+    # Ensure that a warning is emitted.
+    assert (
+        "One or more packages has an associated PGP signature; a future "
+        "version of twine may silently ignore these. See "
+        "https://github.com/pypa/twine/issues/1009 for more information"
+        in caplog.messages
+    )
+
+
 def test_exception_with_only_pre_signed_file(upload_settings, stub_repository):
     """Raise an exception when only a signed file is uploaded."""
     # Upload only pre-signed file