From 43d2ab1408589672e9d4909f7ab2f383ee65aebc Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Mon, 20 Oct 2025 20:46:11 +0000 Subject: [PATCH 1/3] Catch a UniqueViolation instead --- tests/unit/accounts/test_views.py | 7 ++++--- warehouse/accounts/views.py | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/unit/accounts/test_views.py b/tests/unit/accounts/test_views.py index 8c725fb87ebc..f44841897a92 100644 --- a/tests/unit/accounts/test_views.py +++ b/tests/unit/accounts/test_views.py @@ -8,6 +8,7 @@ import pretend import pytest +from psycopg.errors import UniqueViolation from pyramid.httpexceptions import ( HTTPBadRequest, HTTPMovedPermanently, @@ -16,7 +17,7 @@ HTTPTooManyRequests, HTTPUnauthorized, ) -from sqlalchemy.exc import IntegrityError, NoResultFound +from sqlalchemy.exc import NoResultFound from webauthn.authentication.verify_authentication_response import ( VerifiedAuthentication, ) @@ -4569,10 +4570,10 @@ def test_add_pending_oidc_publisher_already_exists( ) ] - def test_add_pending_oidc_publisher_integrityerror(self, monkeypatch, db_request): + def test_add_pending_oidc_publisher_uniqueviolation(self, monkeypatch, db_request): db_request.user = UserFactory.create() EmailFactory(user=db_request.user, verified=True, primary=True) - db_request.db.add = pretend.raiser(IntegrityError("foo", "bar", "baz")) + db_request.db.add = pretend.raiser(UniqueViolation("foo", "bar", "baz")) db_request.registry = pretend.stub( settings={ diff --git a/warehouse/accounts/views.py b/warehouse/accounts/views.py index 7210f68fa63b..14660a3f5ad9 100644 --- a/warehouse/accounts/views.py +++ b/warehouse/accounts/views.py @@ -9,6 +9,7 @@ import pytz from more_itertools import first_true +from psycopg.errors import UniqueViolation from pyramid.httpexceptions import ( HTTPBadRequest, HTTPMovedPermanently, @@ -21,7 +22,7 @@ from pyramid.security import forget, remember from pyramid.view import view_config, view_defaults from sqlalchemy import and_, func, select -from sqlalchemy.exc import IntegrityError, NoResultFound +from sqlalchemy.exc import NoResultFound from webauthn.helpers import bytes_to_base64url from webob.multidict import MultiDict @@ -1772,7 +1773,7 @@ def _add_pending_oidc_publisher( try: self.request.db.add(pending_publisher) self.request.db.flush() # To get the new ID - except IntegrityError: + except UniqueViolation: # The user has probably double-posted and a new publisher was # created after our check for duplicates ran. The success message # is probably already in the flash queue, so just redirect to the From ea6060c0e624808da54e8dd9cde196d89c71d244 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Mon, 20 Oct 2025 20:46:24 +0000 Subject: [PATCH 2/3] Update stale comment --- tests/unit/organizations/test_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/organizations/test_models.py b/tests/unit/organizations/test_models.py index 4a28e1a14b7f..ef78bf419970 100644 --- a/tests/unit/organizations/test_models.py +++ b/tests/unit/organizations/test_models.py @@ -723,7 +723,7 @@ def test_unique_constraint(self, db_session): created_by=admin_user, ) - # Attempt to create duplicate - should raise IntegrityError + # Attempt to create duplicate - should raise UniqueViolation with pytest.raises(psycopg.errors.UniqueViolation): DBOrganizationOIDCIssuerFactory.create( organization=organization, From 64e765afd2902d5046af0378c5a6921394770627 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Mon, 20 Oct 2025 21:09:13 +0000 Subject: [PATCH 3/3] Update translations --- warehouse/locale/messages.pot | 108 +++++++++++++++++----------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/warehouse/locale/messages.pot b/warehouse/locale/messages.pot index 39c2c98fc7db..babf7629b221 100644 --- a/warehouse/locale/messages.pot +++ b/warehouse/locale/messages.pot @@ -122,21 +122,21 @@ msgstr "" msgid "The username isn't valid. Try again." msgstr "" -#: warehouse/accounts/views.py:111 +#: warehouse/accounts/views.py:112 #, python-brace-format msgid "" "There have been too many unsuccessful login attempts. You have been " "locked out for {}. Please try again later." msgstr "" -#: warehouse/accounts/views.py:132 +#: warehouse/accounts/views.py:133 #, python-brace-format msgid "" "Too many emails have been added to this account without verifying them. " "Check your inbox and follow the verification links. (IP: ${ip})" msgstr "" -#: warehouse/accounts/views.py:144 +#: warehouse/accounts/views.py:145 #, python-brace-format msgid "" "Too many password resets have been requested for this account without " @@ -144,189 +144,189 @@ msgid "" " ${ip})" msgstr "" -#: warehouse/accounts/views.py:376 warehouse/accounts/views.py:440 -#: warehouse/accounts/views.py:442 warehouse/accounts/views.py:471 -#: warehouse/accounts/views.py:473 warehouse/accounts/views.py:589 +#: warehouse/accounts/views.py:377 warehouse/accounts/views.py:441 +#: warehouse/accounts/views.py:443 warehouse/accounts/views.py:472 +#: warehouse/accounts/views.py:474 warehouse/accounts/views.py:590 msgid "Invalid or expired two factor login." msgstr "" -#: warehouse/accounts/views.py:434 +#: warehouse/accounts/views.py:435 msgid "Already authenticated" msgstr "" -#: warehouse/accounts/views.py:508 +#: warehouse/accounts/views.py:509 msgid "Successful WebAuthn assertion" msgstr "" -#: warehouse/accounts/views.py:616 warehouse/manage/views/__init__.py:851 +#: warehouse/accounts/views.py:617 warehouse/manage/views/__init__.py:851 msgid "Recovery code accepted. The supplied code cannot be used again." msgstr "" -#: warehouse/accounts/views.py:708 +#: warehouse/accounts/views.py:709 msgid "" "New user registration temporarily disabled. See https://pypi.org/help" "#admin-intervention for details." msgstr "" -#: warehouse/accounts/views.py:877 +#: warehouse/accounts/views.py:878 msgid "Expired token: request a new password reset link" msgstr "" -#: warehouse/accounts/views.py:879 +#: warehouse/accounts/views.py:880 msgid "Invalid token: request a new password reset link" msgstr "" -#: warehouse/accounts/views.py:881 warehouse/accounts/views.py:982 -#: warehouse/accounts/views.py:1088 warehouse/accounts/views.py:1257 +#: warehouse/accounts/views.py:882 warehouse/accounts/views.py:983 +#: warehouse/accounts/views.py:1089 warehouse/accounts/views.py:1258 msgid "Invalid token: no token supplied" msgstr "" -#: warehouse/accounts/views.py:885 +#: warehouse/accounts/views.py:886 msgid "Invalid token: not a password reset token" msgstr "" -#: warehouse/accounts/views.py:890 +#: warehouse/accounts/views.py:891 msgid "Invalid token: user not found" msgstr "" -#: warehouse/accounts/views.py:901 +#: warehouse/accounts/views.py:902 msgid "Invalid token: user has logged in since this token was requested" msgstr "" -#: warehouse/accounts/views.py:919 +#: warehouse/accounts/views.py:920 msgid "" "Invalid token: password has already been changed since this token was " "requested" msgstr "" -#: warehouse/accounts/views.py:950 +#: warehouse/accounts/views.py:951 msgid "You have reset your password" msgstr "" -#: warehouse/accounts/views.py:978 +#: warehouse/accounts/views.py:979 msgid "Expired token: request a new email verification link" msgstr "" -#: warehouse/accounts/views.py:980 +#: warehouse/accounts/views.py:981 msgid "Invalid token: request a new email verification link" msgstr "" -#: warehouse/accounts/views.py:986 +#: warehouse/accounts/views.py:987 msgid "Invalid token: not an email verification token" msgstr "" -#: warehouse/accounts/views.py:995 +#: warehouse/accounts/views.py:996 msgid "Email not found" msgstr "" -#: warehouse/accounts/views.py:998 +#: warehouse/accounts/views.py:999 msgid "Email already verified" msgstr "" -#: warehouse/accounts/views.py:1018 +#: warehouse/accounts/views.py:1019 msgid "You can now set this email as your primary address" msgstr "" -#: warehouse/accounts/views.py:1021 +#: warehouse/accounts/views.py:1022 msgid "This is your primary address" msgstr "" -#: warehouse/accounts/views.py:1027 +#: warehouse/accounts/views.py:1028 #, python-brace-format msgid "Email address ${email_address} verified. ${confirm_message}." msgstr "" -#: warehouse/accounts/views.py:1084 +#: warehouse/accounts/views.py:1085 msgid "Expired token: request a new organization invitation" msgstr "" -#: warehouse/accounts/views.py:1086 +#: warehouse/accounts/views.py:1087 msgid "Invalid token: request a new organization invitation" msgstr "" -#: warehouse/accounts/views.py:1092 +#: warehouse/accounts/views.py:1093 msgid "Invalid token: not an organization invitation token" msgstr "" -#: warehouse/accounts/views.py:1096 +#: warehouse/accounts/views.py:1097 msgid "Organization invitation is not valid." msgstr "" -#: warehouse/accounts/views.py:1105 +#: warehouse/accounts/views.py:1106 msgid "Organization invitation no longer exists." msgstr "" -#: warehouse/accounts/views.py:1157 +#: warehouse/accounts/views.py:1158 #, python-brace-format msgid "Invitation for '${organization_name}' is declined." msgstr "" -#: warehouse/accounts/views.py:1220 +#: warehouse/accounts/views.py:1221 #, python-brace-format msgid "You are now ${role} of the '${organization_name}' organization." msgstr "" -#: warehouse/accounts/views.py:1253 +#: warehouse/accounts/views.py:1254 msgid "Expired token: request a new project role invitation" msgstr "" -#: warehouse/accounts/views.py:1255 +#: warehouse/accounts/views.py:1256 msgid "Invalid token: request a new project role invitation" msgstr "" -#: warehouse/accounts/views.py:1261 +#: warehouse/accounts/views.py:1262 msgid "Invalid token: not a collaboration invitation token" msgstr "" -#: warehouse/accounts/views.py:1265 +#: warehouse/accounts/views.py:1266 msgid "Role invitation is not valid." msgstr "" -#: warehouse/accounts/views.py:1272 +#: warehouse/accounts/views.py:1273 msgid "Invalid token: project does not exist" msgstr "" -#: warehouse/accounts/views.py:1283 +#: warehouse/accounts/views.py:1284 msgid "Role invitation no longer exists." msgstr "" -#: warehouse/accounts/views.py:1315 +#: warehouse/accounts/views.py:1316 #, python-brace-format msgid "Invitation for '${project_name}' is declined." msgstr "" -#: warehouse/accounts/views.py:1381 +#: warehouse/accounts/views.py:1382 #, python-brace-format msgid "You are now ${role} of the '${project_name}' project." msgstr "" -#: warehouse/accounts/views.py:1461 +#: warehouse/accounts/views.py:1462 #, python-brace-format msgid "Please review our updated Terms of Service." msgstr "" -#: warehouse/accounts/views.py:1673 warehouse/accounts/views.py:1927 +#: warehouse/accounts/views.py:1674 warehouse/accounts/views.py:1928 #: warehouse/manage/views/oidc_publishers.py:121 msgid "" "Trusted publishing is temporarily disabled. See https://pypi.org/help" "#admin-intervention for details." msgstr "" -#: warehouse/accounts/views.py:1694 +#: warehouse/accounts/views.py:1695 msgid "disabled. See https://pypi.org/help#admin-intervention for details." msgstr "" -#: warehouse/accounts/views.py:1710 +#: warehouse/accounts/views.py:1711 msgid "" "You must have a verified email in order to register a pending trusted " "publisher. See https://pypi.org/help#openid-connect for details." msgstr "" -#: warehouse/accounts/views.py:1723 +#: warehouse/accounts/views.py:1724 msgid "You can't register more than 3 pending trusted publishers at once." msgstr "" -#: warehouse/accounts/views.py:1738 +#: warehouse/accounts/views.py:1739 #: warehouse/manage/views/oidc_publishers.py:303 #: warehouse/manage/views/oidc_publishers.py:418 #: warehouse/manage/views/oidc_publishers.py:534 @@ -336,7 +336,7 @@ msgid "" "again later." msgstr "" -#: warehouse/accounts/views.py:1748 +#: warehouse/accounts/views.py:1749 #: warehouse/manage/views/oidc_publishers.py:316 #: warehouse/manage/views/oidc_publishers.py:431 #: warehouse/manage/views/oidc_publishers.py:547 @@ -344,22 +344,22 @@ msgstr "" msgid "The trusted publisher could not be registered" msgstr "" -#: warehouse/accounts/views.py:1763 +#: warehouse/accounts/views.py:1764 msgid "" "This trusted publisher has already been registered. Please contact PyPI's" " admins if this wasn't intentional." msgstr "" -#: warehouse/accounts/views.py:1797 +#: warehouse/accounts/views.py:1798 msgid "Registered a new pending publisher to create " msgstr "" -#: warehouse/accounts/views.py:1940 warehouse/accounts/views.py:1953 -#: warehouse/accounts/views.py:1960 +#: warehouse/accounts/views.py:1941 warehouse/accounts/views.py:1954 +#: warehouse/accounts/views.py:1961 msgid "Invalid publisher ID" msgstr "" -#: warehouse/accounts/views.py:1967 +#: warehouse/accounts/views.py:1968 msgid "Removed trusted publisher for project " msgstr ""