From 73812545b83e185d8fbd8b53504033cc8b764af7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 14:05:59 +0000 Subject: [PATCH 1/4] Bump the typing-stubs group with 2 updates Bumps the typing-stubs group with 2 updates: [django-stubs](https://github.com/typeddjango/django-stubs) and [djangorestframework-stubs](https://github.com/typeddjango/djangorestframework-stubs). Updates `django-stubs` from 4.2.6 to 5.0.0 - [Release notes](https://github.com/typeddjango/django-stubs/releases) - [Commits](https://github.com/typeddjango/django-stubs/compare/4.2.6...5.0.0) Updates `djangorestframework-stubs` from 3.14.4 to 3.15.0 - [Release notes](https://github.com/typeddjango/djangorestframework-stubs/releases) - [Commits](https://github.com/typeddjango/djangorestframework-stubs/compare/3.14.4...3.15.0) --- updated-dependencies: - dependency-name: django-stubs dependency-type: direct:production update-type: version-update:semver-major dependency-group: typing-stubs - dependency-name: djangorestframework-stubs dependency-type: direct:production update-type: version-update:semver-minor dependency-group: typing-stubs ... Signed-off-by: dependabot[bot] --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index b4a63ac695..9947034fcc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,8 +53,8 @@ ruff==0.4.3 # type hinting boto3-stubs==1.34.98 botocore-stubs==1.34.94 -django-stubs==4.2.6 -djangorestframework-stubs==3.14.4 +django-stubs==5.0.0 +djangorestframework-stubs==3.15.0 mypy-boto3-ses==1.34.0 mypy==1.10.0 types-pyOpenSSL==24.1.0.20240425 From dddc0ec2648025014cab942bc7a6f0da52d58de6 Mon Sep 17 00:00:00 2001 From: John Whitlock Date: Mon, 6 May 2024 10:46:54 -0500 Subject: [PATCH 2/4] Add Django 5.0 options for force_insert django-stubs 5.0.0 has type hints for Django 5.0. We can support the new signature without using it. --- emails/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/emails/models.py b/emails/models.py index 61ff75028b..93fe7ea23b 100644 --- a/emails/models.py +++ b/emails/models.py @@ -16,6 +16,7 @@ from django.core.exceptions import BadRequest from django.core.validators import MinLengthValidator from django.db import models, transaction +from django.db.models.base import ModelBase from django.db.models.query import QuerySet from django.dispatch import receiver from django.utils.translation.trans_real import ( @@ -141,7 +142,7 @@ def __str__(self): def save( self, - force_insert: bool = False, + force_insert: bool | tuple[ModelBase, ...] = False, force_update: bool = False, using: str | None = None, update_fields: Iterable[str] | None = None, @@ -791,7 +792,7 @@ def delete(self, *args, **kwargs): def save( self, - force_insert: bool = False, + force_insert: bool | tuple[ModelBase, ...] = False, force_update: bool = False, using: str | None = None, update_fields: Iterable[str] | None = None, @@ -935,7 +936,7 @@ def __str__(self): def save( self, - force_insert: bool = False, + force_insert: bool | tuple[ModelBase, ...] = False, force_update: bool = False, using: str | None = None, update_fields: Iterable[str] | None = None, From 0b9d26e638f6478be164c1baa3ec2f4fd744ecfe Mon Sep 17 00:00:00 2001 From: John Whitlock Date: Mon, 6 May 2024 11:01:58 -0500 Subject: [PATCH 3/4] Complete function types --- api/serializers/phones.py | 8 +++++--- api/tests/emails_views_tests.py | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/api/serializers/phones.py b/api/serializers/phones.py index b06e52d72f..7413fc0e0c 100644 --- a/api/serializers/phones.py +++ b/api/serializers/phones.py @@ -1,3 +1,5 @@ +from typing import Any + from rest_framework import serializers from phones.models import InboundContact, RealPhone, RelayNumber @@ -104,7 +106,7 @@ class TwilioInboundSmsSerializer(serializers.Serializer): from_ = serializers.CharField() to = serializers.CharField() - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) # Change to reserved keyword "from" self.fields["from"] = self.fields.pop("from_") @@ -116,7 +118,7 @@ class TwilioMessagesSerializer(serializers.Serializer): date_sent = serializers.CharField() body = serializers.CharField() - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) # Change to reserved keyword "from" self.fields["from"] = self.fields.pop("from_") @@ -156,7 +158,7 @@ class IqInboundSmsSerializer(serializers.Serializer): from_ = serializers.CharField() to = serializers.CharField() - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) # Change to reserved keyword "from" self.fields["from"] = self.fields.pop("from_") diff --git a/api/tests/emails_views_tests.py b/api/tests/emails_views_tests.py index 6b273e4fdc..da3256acf7 100644 --- a/api/tests/emails_views_tests.py +++ b/api/tests/emails_views_tests.py @@ -3,6 +3,7 @@ from unittest.mock import patch from django.contrib.auth.models import User +from django.test import Client from django.urls import reverse from django.utils import timezone @@ -731,7 +732,7 @@ def test_delete_randomaddress( assert event == expected_event -def test_first_forwarded_email_unauth(client) -> None: +def test_first_forwarded_email_unauth(client: Client) -> None: response = client.post("/api/v1/first-forwarded-email/") assert response.status_code == 401 assert response.json() == {"detail": str(NotAuthenticated())} From 91f9f1e50409f2e0c2cd760801379a72c0e0db95 Mon Sep 17 00:00:00 2001 From: John Whitlock Date: Mon, 6 May 2024 11:02:27 -0500 Subject: [PATCH 4/4] Fix ruff UP031 --- api/authentication.py | 4 ++-- emails/models.py | 2 +- emails/tests/models_tests.py | 2 +- emails/utils.py | 2 +- emails/views.py | 10 ++++++---- phones/models.py | 8 ++++---- privaterelay/apps.py | 2 +- privaterelay/settings.py | 2 +- pyproject.toml | 2 ++ 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/api/authentication.py b/api/authentication.py index 64f9171228..b3dfe6b405 100644 --- a/api/authentication.py +++ b/api/authentication.py @@ -18,8 +18,8 @@ ) logger = logging.getLogger("events") -INTROSPECT_TOKEN_URL = ( - "%s/introspect" % settings.SOCIALACCOUNT_PROVIDERS["fxa"]["OAUTH_ENDPOINT"] +INTROSPECT_TOKEN_URL = "{}/introspect".format( + settings.SOCIALACCOUNT_PROVIDERS["fxa"]["OAUTH_ENDPOINT"] ) diff --git a/emails/models.py b/emails/models.py index 93fe7ea23b..a9f17e00b2 100644 --- a/emails/models.py +++ b/emails/models.py @@ -138,7 +138,7 @@ class Profile(models.Model): last_engagement = models.DateTimeField(blank=True, null=True, db_index=True) def __str__(self): - return "%s Profile" % self.user + return f"{self.user} Profile" def save( self, diff --git a/emails/tests/models_tests.py b/emails/tests/models_tests.py index 1f628e363e..adcdab351e 100644 --- a/emails/tests/models_tests.py +++ b/emails/tests/models_tests.py @@ -1372,7 +1372,7 @@ def test_make_domain_address_makes_different_addresses(self): # not been fixed yet for i in range(5): domain_address = DomainAddress.make_domain_address( - self.user_profile, "test-different-%s" % i + self.user_profile, f"test-different-{i}" ) assert domain_address.first_emailed_at is None domain_addresses = DomainAddress.objects.filter(user=self.user).values_list( diff --git a/emails/utils.py b/emails/utils.py index 8f68813003..63ad3585a8 100644 --- a/emails/utils.py +++ b/emails/utils.py @@ -255,7 +255,7 @@ def get_reply_to_address(premium: bool = True) -> str: """Return the address that relays replies.""" if premium: _, reply_to_address = parseaddr( - "replies@%s" % get_domains_from_settings().get("RELAY_FIREFOX_DOMAIN") + "replies@{}".format(get_domains_from_settings().get("RELAY_FIREFOX_DOMAIN")) ) else: _, reply_to_address = parseaddr(settings.RELAY_FROM_ADDRESS) diff --git a/emails/views.py b/emails/views.py index c5a6f429af..0f268f6f73 100644 --- a/emails/views.py +++ b/emails/views.py @@ -443,8 +443,10 @@ def _sns_notification(json_body): }, ) return HttpResponse( - "Received SNS notification for unsupported Type: %s" - % html.escape(shlex.quote(notification_type)), + ( + "Received SNS notification for unsupported Type: " + f"{html.escape(shlex.quote(notification_type))}" + ), status=400, ) response = _sns_message(message_json) @@ -641,7 +643,7 @@ def _handle_received(message_json: AWS_SNSMessageJSON) -> HttpResponse: bounce_paused, bounce_type = user_profile.check_bounce_pause() if bounce_paused: _record_receipt_verdicts(receipt, "user_bounce_paused") - incr_if_enabled("email_suppressed_for_%s_bounce" % bounce_type, 1) + incr_if_enabled(f"email_suppressed_for_{bounce_type}_bounce", 1) reason: Literal["soft_bounce_pause", "hard_bounce_pause"] = ( "soft_bounce_pause" if bounce_type == "soft" else "hard_bounce_pause" ) @@ -814,7 +816,7 @@ def _handle_received(message_json: AWS_SNSMessageJSON) -> HttpResponse: def _get_verdict(receipt, verdict_type): - return receipt["%sVerdict" % verdict_type]["status"] + return receipt[f"{verdict_type}Verdict"]["status"] def _check_email_from_list(headers): diff --git a/phones/models.py b/phones/models.py index f3f57d21bd..530aca3827 100644 --- a/phones/models.py +++ b/phones/models.py @@ -449,7 +449,7 @@ def suggested_numbers(user): # TODO: can we make multiple pattern searches in a single Twilio API request same_prefix_options = [] # look for numbers with same area code and 3-number prefix - contains = "%s****" % real_num[:8] if real_num else "" + contains = f"{real_num[:8]}****" if real_num else "" twilio_nums = avail_nums.local.list(contains=contains, limit=10) same_prefix_options.extend(convert_twilio_numbers_to_dict(twilio_nums)) @@ -459,17 +459,17 @@ def suggested_numbers(user): same_prefix_options.extend(convert_twilio_numbers_to_dict(twilio_nums)) # look for numbers with same area code and 1-number prefix - contains = "%s******" % real_num[:6] if real_num else "" + contains = f"{real_num[:6]}******" if real_num else "" twilio_nums = avail_nums.local.list(contains=contains, limit=10) same_prefix_options.extend(convert_twilio_numbers_to_dict(twilio_nums)) # look for same number in other area codes - contains = "+1***%s" % real_num[5:] if real_num else "" + contains = f"+1***{real_num[5:]}" if real_num else "" twilio_nums = avail_nums.local.list(contains=contains, limit=10) other_areas_options = convert_twilio_numbers_to_dict(twilio_nums) # look for any numbers in the area code - contains = "%s*******" % real_num[:5] if real_num else "" + contains = f"{real_num[:5]}*******" if real_num else "" twilio_nums = avail_nums.local.list(contains=contains, limit=10) same_area_options = convert_twilio_numbers_to_dict(twilio_nums) diff --git a/privaterelay/apps.py b/privaterelay/apps.py index 18f9381e4f..2fc476d8ae 100644 --- a/privaterelay/apps.py +++ b/privaterelay/apps.py @@ -92,7 +92,7 @@ def ready(self) -> None: @cached_property def fxa_verifying_keys(self) -> list[dict[str, Any]]: resp = requests.get( - "%s/jwks" % settings.SOCIALACCOUNT_PROVIDERS["fxa"]["OAUTH_ENDPOINT"] + "{}/jwks".format(settings.SOCIALACCOUNT_PROVIDERS["fxa"]["OAUTH_ENDPOINT"]) ) if resp.status_code == 200: keys: list[dict[str, Any]] = resp.json()["keys"] diff --git a/privaterelay/settings.py b/privaterelay/settings.py index 845b11a058..0bb0b12940 100644 --- a/privaterelay/settings.py +++ b/privaterelay/settings.py @@ -453,7 +453,7 @@ def _get_initial_middleware() -> list[str]: DATABASES = { "default": dj_database_url.config( - default="sqlite:///%s" % os.path.join(BASE_DIR, "db.sqlite3") + default="sqlite:///{}".format(os.path.join(BASE_DIR, "db.sqlite3")) ) } # Optionally set a test database name. diff --git a/pyproject.toml b/pyproject.toml index f37bcdc50d..b0b32a5271 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,6 +117,8 @@ extend-safe-fixes = [ # E712 Avoid equality comparisons to True / False # Changes '== True' to 'is True' "E712", + # UP031 Use format specifiers instead of percent format + "UP031", ] [tool.ruff.lint.isort]