diff --git a/app/authentication/auth.py b/app/authentication/auth.py index 3d2ebdd5b..cf4ad6fb4 100644 --- a/app/authentication/auth.py +++ b/app/authentication/auth.py @@ -29,6 +29,7 @@ GENERAL_TOKEN_ERROR_MESSAGE = TOKEN_MESSAGE_ONE + TOKEN_MESSAGE_TWO class AuthError(Exception): def __init__(self, message, code, service_id=None, api_key_id=None): + super().__init__(message, code, service_id, api_key_id) self.message = {"token": [message]} self.short_message = message self.code = code diff --git a/app/clients/document_download.py b/app/clients/document_download.py index 7211d716d..c07829371 100644 --- a/app/clients/document_download.py +++ b/app/clients/document_download.py @@ -4,6 +4,7 @@ from flask import current_app class DocumentDownloadError(Exception): def __init__(self, message, status_code): + super().__init__(message, status_code) self.message = message self.status_code = status_code diff --git a/app/clients/sms/__init__.py b/app/clients/sms/__init__.py index f3a366648..5eded7cc4 100644 --- a/app/clients/sms/__init__.py +++ b/app/clients/sms/__init__.py @@ -10,6 +10,7 @@ class SmsClientResponseException(ClientException): """ def __init__(self, message): + super().__init__(message) self.message = message def __str__(self): diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index dcc9e1f76..ae5b6214e 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -699,7 +699,9 @@ def query_organization_sms_usage_for_year(organization_id, year): ) -def fetch_usage_year_for_organization(organization_id, year, include_all_services=False): +def fetch_usage_year_for_organization( + organization_id, year, include_all_services=False +): year_start, year_end = get_calendar_year_dates(year) today = utc_now().date() diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index cc8c29424..fcf802535 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -351,10 +351,7 @@ def dao_get_notification_counts_for_organization(service_ids, current_year): end_date = datetime(current_year + 1, 6, 16) stmt1 = ( - select( - Notification.service_id, - func.count().label("count") - ) + select(Notification.service_id, func.count().label("count")) .where( Notification.service_id.in_(service_ids), Notification.status @@ -370,10 +367,7 @@ def dao_get_notification_counts_for_organization(service_ids, current_year): ) stmt2 = ( - select( - NotificationHistory.service_id, - func.count().label("count") - ) + select(NotificationHistory.service_id, func.count().label("count")) .where( NotificationHistory.service_id.in_(service_ids), NotificationHistory.status diff --git a/app/errors.py b/app/errors.py index 10f88eac5..ae6efbb86 100644 --- a/app/errors.py +++ b/app/errors.py @@ -15,7 +15,7 @@ class InvalidRequest(Exception): fields = [] def __init__(self, message, status_code): - super().__init__() + super().__init__(message, status_code) self.message = message self.status_code = status_code @@ -115,16 +115,20 @@ class TooManyRequestsError(InvalidRequest): status_code = 429 message_template = "Exceeded send limits ({}) for today" - def __init__(self, sending_limit): + def __init__(self, sending_limit): # noqa: B042 self.message = self.message_template.format(sending_limit) + self.sending_limit = sending_limit + super().__init__(self.message, self.status_code) class TotalRequestsError(InvalidRequest): status_code = 429 message_template = "Exceeded total application limits ({}) for today" - def __init__(self, sending_limit): + def __init__(self, sending_limit): # noqa: B042 self.message = self.message_template.format(sending_limit) + self.sending_limit = sending_limit + super().__init__(self.message, self.status_code) class RateLimitError(InvalidRequest): @@ -133,7 +137,7 @@ class RateLimitError(InvalidRequest): "Exceeded rate limit for key type {} of {} requests per {} seconds" ) - def __init__(self, sending_limit, interval, key_type): + def __init__(self, sending_limit, interval, key_type): # noqa: B042 # normal keys are spoken of as "live" in the documentation # so using this in the error messaging if key_type == KeyType.NORMAL: @@ -142,12 +146,17 @@ class RateLimitError(InvalidRequest): self.message = self.message_template.format( key_type.upper(), sending_limit, interval ) + self.sending_limit = sending_limit + self.interval = interval + self.key_type = key_type + super().__init__(self.message, self.status_code) class BadRequestError(InvalidRequest): message = "An error occurred" - def __init__(self, fields=None, message=None, status_code=400): - self.status_code = status_code + def __init__(self, fields=None, message=None, status_code=400): # noqa: B042 self.fields = fields or [] self.message = message if message else self.message + self.status_code = status_code + super().__init__(self.message, self.status_code) diff --git a/app/exceptions.py b/app/exceptions.py index bfbcb87de..799b80dd7 100644 --- a/app/exceptions.py +++ b/app/exceptions.py @@ -1,5 +1,6 @@ class DVLAException(Exception): def __init__(self, message): + super().__init__(message) self.message = message diff --git a/app/organization/rest.py b/app/organization/rest.py index 3296ff48f..bc7acd3b6 100644 --- a/app/organization/rest.py +++ b/app/organization/rest.py @@ -153,7 +153,9 @@ def get_organization_services_usage(organization_id): return jsonify(result="error", message="No valid year provided"), 400 include_all = request.args.get("include_all_services", "false").lower() == "true" - services = fetch_usage_year_for_organization(organization_id, year, include_all_services=include_all) + services = fetch_usage_year_for_organization( + organization_id, year, include_all_services=include_all + ) list_services = services.values() sorted_services = sorted( list_services, key=lambda s: (-s["active"], s["service_name"].lower()) @@ -266,7 +268,9 @@ def send_notifications_on_mou_signed(organization_id): ) -@organization_blueprint.route("//message-allowance", methods=["GET"]) +@organization_blueprint.route( + "//message-allowance", methods=["GET"] +) def get_organization_message_allowance(organization_id): check_suspicious_id(organization_id) @@ -276,11 +280,16 @@ def get_organization_message_allowance(organization_id): services = dao_get_organization_services(organization_id) if not services: - return jsonify({ - "messages_sent": 0, - "messages_remaining": 0, - "total_message_limit": 0, - }), 200 + return ( + jsonify( + { + "messages_sent": 0, + "messages_remaining": 0, + "total_message_limit": 0, + } + ), + 200, + ) current_year = datetime.now(tz=ZoneInfo("UTC")).year service_ids = [service.id for service in services] @@ -293,8 +302,13 @@ def get_organization_message_allowance(organization_id): total_message_limit = sum(s.total_message_limit for s in services) total_messages_remaining = total_message_limit - total_messages_sent - return jsonify({ - "messages_sent": total_messages_sent, - "messages_remaining": total_messages_remaining, - "total_message_limit": total_message_limit, - }), 200 + return ( + jsonify( + { + "messages_sent": total_messages_sent, + "messages_remaining": total_messages_remaining, + "total_message_limit": total_message_limit, + } + ), + 200, + ) diff --git a/notifications_python_client/errors.py b/notifications_python_client/errors.py index 430123684..d6f7c454a 100644 --- a/notifications_python_client/errors.py +++ b/notifications_python_client/errors.py @@ -18,6 +18,7 @@ class TokenError(Exception): else TOKEN_ERROR_DEFAULT_ERROR_MESSAGE ) self.token = token + super().__init__(self.message, token) class TokenExpiredError(TokenError): @@ -48,6 +49,7 @@ class APIError(Exception): def __init__(self, response: Response = None, message: str = None): self.response = response self._message = message + super().__init__(response, message) def __str__(self): return f"{self.status_code} - {self.message}" diff --git a/notifications_utils/clients/antivirus/antivirus_client.py b/notifications_utils/clients/antivirus/antivirus_client.py index affe8f27e..9bbd90bd0 100644 --- a/notifications_utils/clients/antivirus/antivirus_client.py +++ b/notifications_utils/clients/antivirus/antivirus_client.py @@ -4,6 +4,7 @@ from flask import current_app class AntivirusError(Exception): def __init__(self, message=None, status_code=None): + super().__init__(message, status_code) self.message = message self.status_code = status_code diff --git a/notifications_utils/clients/zendesk/zendesk_client.py b/notifications_utils/clients/zendesk/zendesk_client.py index c5c2c5d02..be13c85d0 100644 --- a/notifications_utils/clients/zendesk/zendesk_client.py +++ b/notifications_utils/clients/zendesk/zendesk_client.py @@ -4,6 +4,7 @@ from flask import current_app class ZendeskError(Exception): def __init__(self, response): + super().__init__(str(response)) self.response = response diff --git a/poetry.lock b/poetry.lock index 54c84ff95..b9b57530d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -1527,19 +1527,19 @@ pyflakes = ">=3.4.0,<3.5.0" [[package]] name = "flake8-bugbear" -version = "24.12.12" +version = "25.10.21" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." optional = false -python-versions = ">=3.8.1" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "flake8_bugbear-24.12.12-py3-none-any.whl", hash = "sha256:1b6967436f65ca22a42e5373aaa6f2d87966ade9aa38d4baf2a1be550767545e"}, - {file = "flake8_bugbear-24.12.12.tar.gz", hash = "sha256:46273cef0a6b6ff48ca2d69e472f41420a42a46e24b2a8972e4f0d6733d12a64"}, + {file = "flake8_bugbear-25.10.21-py3-none-any.whl", hash = "sha256:f1c5654f9d9d3e62e90da1f0335551fdbc565c51749713177dbcfb9edb105405"}, + {file = "flake8_bugbear-25.10.21.tar.gz", hash = "sha256:2876afcaed8bfb3464cf33e3ec42cc3bec0a004165b84400dc3392b0547c2714"}, ] [package.dependencies] attrs = ">=22.2.0" -flake8 = ">=6.0.0" +flake8 = ">=7.2.0" [package.extras] dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] @@ -5926,4 +5926,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = "^3.13.2" -content-hash = "66d1fa0da9127a0c439a29ac4a8fdd83f9d3e9ae5c062a3441c6225ef534eed9" +content-hash = "ace53071110003d43f585c505356b2abb531eaf5196ea1669e2ed2ed7ffc9fb3" diff --git a/pyproject.toml b/pyproject.toml index d8a8c205d..5ef0bbc5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,7 +90,7 @@ cyclonedx-python-lib = "^11.4.0" cloudfoundry-client = "*" exceptiongroup = "==1.3.0" flake8 = "^7.3.0" -flake8-bugbear = "^24.12.12" +flake8-bugbear = "^25.10.21" freezegun = "^1.5.5" hypothesis = "^6.142.3" honcho = "*" diff --git a/tests/app/organization/test_rest.py b/tests/app/organization/test_rest.py index 698fbe3c3..48ad241c4 100644 --- a/tests/app/organization/test_rest.py +++ b/tests/app/organization/test_rest.py @@ -963,7 +963,9 @@ def test_get_organization_message_allowance(admin_request, sample_organization, mock_get_counts.assert_called_once_with([service_1.id, service_2.id], 2025) -def test_get_organization_message_allowance_no_services(admin_request, sample_organization): +def test_get_organization_message_allowance_no_services( + admin_request, sample_organization +): response = admin_request.get( "organization.get_organization_message_allowance", organization_id=sample_organization.id,