From 143baa42432cde9f288bd202336ef2b11172f6e4 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Mon, 17 Jul 2023 13:40:33 -0700 Subject: [PATCH] python: Convert translated positional {} fields to {named} fields. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translators benefit from the extra information in the field names, and need the reordering freedom that isn’t available with multiple positional fields. Signed-off-by: Anders Kaseorg --- analytics/views/stats.py | 2 +- corporate/lib/stripe.py | 11 +++++++---- tools/semgrep.yml | 16 ++++++++++++++++ zerver/actions/default_streams.py | 28 ++++++++++++++++++++-------- zerver/actions/message_flags.py | 8 +++++--- zerver/actions/typing.py | 2 +- zerver/actions/user_groups.py | 4 ++-- zerver/forms.py | 4 ++-- zerver/lib/addressee.py | 4 ++-- zerver/lib/emoji.py | 2 +- zerver/lib/narrow.py | 2 +- zerver/lib/push_notifications.py | 8 ++++---- zerver/lib/remote_server.py | 2 +- zerver/lib/request.py | 4 +++- zerver/lib/streams.py | 22 +++++++++++++++------- zerver/lib/string_validation.py | 12 +++++++++--- zerver/lib/user_groups.py | 28 +++++++++++++++++++++------- zerver/lib/users.py | 18 ++++++++++++------ zerver/lib/validator.py | 2 +- zerver/lib/webhooks/common.py | 4 +++- zerver/lib/zcommand.py | 2 +- zerver/models.py | 14 +++++++++----- zerver/views/events_register.py | 6 ++++-- zerver/views/hotspots.py | 2 +- zerver/views/invite.py | 10 ++++++++-- zerver/views/message_fetch.py | 4 ++-- zerver/views/message_flags.py | 2 +- zerver/views/presence.py | 2 +- zerver/views/realm.py | 12 +++++++++--- zerver/views/realm_domains.py | 2 +- zerver/views/realm_emoji.py | 8 +++++--- zerver/views/realm_icon.py | 4 ++-- zerver/views/realm_logo.py | 4 ++-- zerver/views/streams.py | 8 ++++++-- zerver/views/upload.py | 4 ++-- zerver/views/user_groups.py | 4 +++- zerver/views/user_settings.py | 18 +++++++++++------- zerver/views/users.py | 2 +- zerver/webhooks/wordpress/view.py | 2 +- zilencer/views.py | 4 ++-- 40 files changed, 199 insertions(+), 98 deletions(-) diff --git a/analytics/views/stats.py b/analytics/views/stats.py index cf05e23624..963358e262 100644 --- a/analytics/views/stats.py +++ b/analytics/views/stats.py @@ -315,7 +315,7 @@ def get_chart_data( labels_sort_function = None include_empty_subgroups = True else: - raise JsonableError(_("Unknown chart name: {}").format(chart_name)) + raise JsonableError(_("Unknown chart name: {chart_name}").format(chart_name=chart_name)) # Most likely someone using our API endpoint. The /stats page does not # pass a start or end in its requests. diff --git a/corporate/lib/stripe.py b/corporate/lib/stripe.py index c3112d54db..6f219e2140 100644 --- a/corporate/lib/stripe.py +++ b/corporate/lib/stripe.py @@ -109,14 +109,17 @@ def validate_licenses( if licenses is None or (not exempt_from_license_number_check and licenses < min_licenses): raise BillingError( - "not enough licenses", _("You must invoice for at least {} users.").format(min_licenses) + "not enough licenses", + _("You must invoice for at least {min_licenses} users.").format( + min_licenses=min_licenses + ), ) if max_licenses is not None and licenses > max_licenses: message = _( - "Invoices with more than {} licenses can't be processed from this page. To complete " - "the upgrade, please contact {}." - ).format(max_licenses, settings.ZULIP_ADMINISTRATOR) + "Invoices with more than {max_licenses} licenses can't be processed from this page. To" + " complete the upgrade, please contact {email}." + ).format(max_licenses=max_licenses, email=settings.ZULIP_ADMINISTRATOR) raise BillingError("too many licenses", message) diff --git a/tools/semgrep.yml b/tools/semgrep.yml index 818805fc1b..8fee591531 100644 --- a/tools/semgrep.yml +++ b/tools/semgrep.yml @@ -76,6 +76,20 @@ rules: severity: ERROR message: "Immediately formatting a lazily translated string destroys its laziness" + - id: translated-positional-field + languages: [python] + patterns: + - pattern-either: + - pattern: django.utils.translation.gettext("$MESSAGE") + - pattern: django.utils.translation.pgettext($CONTEXT, "$MESSAGE") + - pattern: django.utils.translation.gettext_lazy("$MESSAGE") + - pattern: django.utils.translation.pgettext_lazy($CONTEXT, "$MESSAGE") + - metavariable-regex: + metavariable: $MESSAGE + regex: (^|.*[^{])(\{\{)*\{[:!}].* + severity: ERROR + message: "Prefer {named} fields over positional {} in translated strings" + - id: mutable-default-type languages: [python] pattern-either: @@ -99,7 +113,9 @@ rules: pattern-either: - pattern: '"..." % ...' - pattern: django.utils.translation.gettext(...) % ... + - pattern: django.utils.translation.pgettext(...) % ... - pattern: django.utils.translation.gettext_lazy(...) % ... + - pattern: django.utils.translation.pgettext_lazy(...) % ... severity: ERROR message: "Prefer f-strings or .format for string formatting" diff --git a/zerver/actions/default_streams.py b/zerver/actions/default_streams.py index 79518487a0..467d278648 100644 --- a/zerver/actions/default_streams.py +++ b/zerver/actions/default_streams.py @@ -21,18 +21,22 @@ from zerver.tornado.django_api import send_event_on_commit def check_default_stream_group_name(group_name: str) -> None: if group_name.strip() == "": - raise JsonableError(_("Invalid default stream group name '{}'").format(group_name)) + raise JsonableError( + _("Invalid default stream group name '{group_name}'").format(group_name=group_name) + ) if len(group_name) > DefaultStreamGroup.MAX_NAME_LENGTH: raise JsonableError( - _("Default stream group name too long (limit: {} characters)").format( - DefaultStreamGroup.MAX_NAME_LENGTH, + _("Default stream group name too long (limit: {max_length} characters)").format( + max_length=DefaultStreamGroup.MAX_NAME_LENGTH, ) ) for i in group_name: if ord(i) == 0: raise JsonableError( - _("Default stream group name '{}' contains NULL (0x00) characters.").format( - group_name, + _( + "Default stream group name '{group_name}' contains NULL (0x00) characters." + ).format( + group_name=group_name, ) ) @@ -45,7 +49,9 @@ def lookup_default_stream_groups( try: default_stream_group = DefaultStreamGroup.objects.get(name=group_name, realm=realm) except DefaultStreamGroup.DoesNotExist: - raise JsonableError(_("Invalid default stream group {}").format(group_name)) + raise JsonableError( + _("Invalid default stream group {group_name}").format(group_name=group_name) + ) default_stream_groups.append(default_stream_group) return default_stream_groups @@ -157,11 +163,17 @@ def do_change_default_stream_group_name( ) -> None: if group.name == new_group_name: raise JsonableError( - _("This default stream group is already named '{}'").format(new_group_name) + _("This default stream group is already named '{group_name}'").format( + group_name=new_group_name + ) ) if DefaultStreamGroup.objects.filter(name=new_group_name, realm=realm).exists(): - raise JsonableError(_("Default stream group '{}' already exists").format(new_group_name)) + raise JsonableError( + _("Default stream group '{group_name}' already exists").format( + group_name=new_group_name + ) + ) group.name = new_group_name group.save() diff --git a/zerver/actions/message_flags.py b/zerver/actions/message_flags.py index 4fb0be08b0..f10f86c1f6 100644 --- a/zerver/actions/message_flags.py +++ b/zerver/actions/message_flags.py @@ -254,11 +254,13 @@ def do_update_message_flags( ) -> int: valid_flags = [item for item in UserMessage.flags if item not in UserMessage.NON_API_FLAGS] if flag not in valid_flags: - raise JsonableError(_("Invalid flag: '{}'").format(flag)) + raise JsonableError(_("Invalid flag: '{flag}'").format(flag=flag)) if flag in UserMessage.NON_EDITABLE_FLAGS: - raise JsonableError(_("Flag not editable: '{}'").format(flag)) + raise JsonableError(_("Flag not editable: '{flag}'").format(flag=flag)) if operation not in ("add", "remove"): - raise JsonableError(_("Invalid message flag operation: '{}'").format(operation)) + raise JsonableError( + _("Invalid message flag operation: '{operation}'").format(operation=operation) + ) is_adding = operation == "add" flagattr = getattr(UserMessage.flags, flag) flag_target = flagattr if is_adding else 0 diff --git a/zerver/actions/typing.py b/zerver/actions/typing.py index 0a103f9610..f18ddf020b 100644 --- a/zerver/actions/typing.py +++ b/zerver/actions/typing.py @@ -52,7 +52,7 @@ def check_send_typing_notification(sender: UserProfile, user_ids: List[int], ope # is relevant here. user_profile = get_user_by_id_in_realm_including_cross_realm(user_id, sender.realm) except UserProfile.DoesNotExist: - raise JsonableError(_("Invalid user ID {}").format(user_id)) + raise JsonableError(_("Invalid user ID {user_id}").format(user_id=user_id)) user_profiles.append(user_profile) do_send_typing_notification( diff --git a/zerver/actions/user_groups.py b/zerver/actions/user_groups.py index a42f92f8db..9ce26165d1 100644 --- a/zerver/actions/user_groups.py +++ b/zerver/actions/user_groups.py @@ -210,7 +210,7 @@ def check_add_user_group( do_send_create_user_group_event(user_group, initial_members) return user_group except django.db.utils.IntegrityError: - raise JsonableError(_("User group '{}' already exists.").format(name)) + raise JsonableError(_("User group '{group_name}' already exists.").format(group_name=name)) def do_send_user_group_update_event( @@ -242,7 +242,7 @@ def do_update_user_group_name( ).decode(), ) except django.db.utils.IntegrityError: - raise JsonableError(_("User group '{}' already exists.").format(name)) + raise JsonableError(_("User group '{group_name}' already exists.").format(group_name=name)) do_send_user_group_update_event(user_group, dict(name=name)) diff --git a/zerver/forms.py b/zerver/forms.py index 16d90d0028..4c32272f4e 100644 --- a/zerver/forms.py +++ b/zerver/forms.py @@ -494,10 +494,10 @@ class OurAuthenticationForm(AuthenticationForm): secs_to_freedom = int(e.secs_to_freedom) error_message = _( "You're making too many attempts to sign in." - " Try again in {} seconds or contact your organization administrator" + " Try again in {seconds} seconds or contact your organization administrator" " for help." ) - raise ValidationError(error_message.format(secs_to_freedom)) + raise ValidationError(error_message.format(seconds=secs_to_freedom)) if return_data.get("inactive_realm"): raise AssertionError("Programming error: inactive realm in authentication form") diff --git a/zerver/lib/addressee.py b/zerver/lib/addressee.py index 3fe8395516..567e021664 100644 --- a/zerver/lib/addressee.py +++ b/zerver/lib/addressee.py @@ -19,7 +19,7 @@ def get_user_profiles(emails: Iterable[str], realm: Realm) -> List[UserProfile]: try: user_profile = get_user_including_cross_realm(email, realm) except UserProfile.DoesNotExist: - raise JsonableError(_("Invalid email '{}'").format(email)) + raise JsonableError(_("Invalid email '{email}'").format(email=email)) user_profiles.append(user_profile) return user_profiles @@ -30,7 +30,7 @@ def get_user_profiles_by_ids(user_ids: Iterable[int], realm: Realm) -> List[User try: user_profile = get_user_by_id_in_realm_including_cross_realm(user_id, realm) except UserProfile.DoesNotExist: - raise JsonableError(_("Invalid user ID {}").format(user_id)) + raise JsonableError(_("Invalid user ID {user_id}").format(user_id=user_id)) user_profiles.append(user_profile) return user_profiles diff --git a/zerver/lib/emoji.py b/zerver/lib/emoji.py index 43be22036c..818fd72e0c 100644 --- a/zerver/lib/emoji.py +++ b/zerver/lib/emoji.py @@ -85,7 +85,7 @@ def get_emoji_data(realm_id: int, emoji_name: str) -> EmojiData: emoji_code = name_to_codepoint[emoji_name] return EmojiData(emoji_code=emoji_code, reaction_type=Reaction.UNICODE_EMOJI) - raise JsonableError(_("Emoji '{}' does not exist").format(emoji_name)) + raise JsonableError(_("Emoji '{emoji_name}' does not exist").format(emoji_name=emoji_name)) def check_emoji_request(realm: Realm, emoji_name: str, emoji_code: str, emoji_type: str) -> None: diff --git a/zerver/lib/narrow.py b/zerver/lib/narrow.py index 5ff943dfbf..64acd4a2b7 100644 --- a/zerver/lib/narrow.py +++ b/zerver/lib/narrow.py @@ -105,7 +105,7 @@ def check_narrow_for_events(narrow: Collection[NarrowTerm]) -> None: for narrow_term in narrow: operator = narrow_term.operator if operator not in ["stream", "topic", "sender", "is"]: - raise JsonableError(_("Operator {} not supported.").format(operator)) + raise JsonableError(_("Operator {operator} not supported.").format(operator=operator)) def is_spectator_compatible(narrow: Iterable[Dict[str, Any]]) -> bool: diff --git a/zerver/lib/push_notifications.py b/zerver/lib/push_notifications.py index 46aeeee38b..604b3d3ed5 100644 --- a/zerver/lib/push_notifications.py +++ b/zerver/lib/push_notifications.py @@ -338,8 +338,8 @@ def parse_gcm_options(options: Dict[str, Any], data: Dict[str, Any]) -> str: if priority not in ("normal", "high"): raise JsonableError( _( - "Invalid GCM option to bouncer: priority {!r}", - ).format(priority) + "Invalid GCM option to bouncer: priority {priority!r}", + ).format(priority=priority) ) if options: @@ -348,8 +348,8 @@ def parse_gcm_options(options: Dict[str, Any], data: Dict[str, Any]) -> str: # one-way compatibility. raise JsonableError( _( - "Invalid GCM options to bouncer: {}", - ).format(orjson.dumps(options).decode()) + "Invalid GCM options to bouncer: {options}", + ).format(options=orjson.dumps(options).decode()) ) return priority # when this grows a second option, can make it a tuple diff --git a/zerver/lib/remote_server.py b/zerver/lib/remote_server.py index a12f1f79dd..61e20030c5 100644 --- a/zerver/lib/remote_server.py +++ b/zerver/lib/remote_server.py @@ -90,7 +90,7 @@ def send_to_push_bouncer( if "code" in result_dict and result_dict["code"] == "INVALID_ZULIP_SERVER": # Invalid Zulip server credentials should email this server's admins raise PushNotificationBouncerError( - _("Push notifications bouncer error: {}").format(msg) + _("Push notifications bouncer error: {error}").format(error=msg) ) else: # But most other errors coming from the push bouncer diff --git a/zerver/lib/request.py b/zerver/lib/request.py index 3203b2da99..03b4732d64 100644 --- a/zerver/lib/request.py +++ b/zerver/lib/request.py @@ -439,7 +439,9 @@ def has_request_variables( except orjson.JSONDecodeError: if param.argument_type == "body": raise InvalidJSONError(_("Malformed JSON")) - raise JsonableError(_('Argument "{}" is not valid JSON.').format(post_var_name)) + raise JsonableError( + _('Argument "{name}" is not valid JSON.').format(name=post_var_name) + ) try: val = param.json_validator(post_var_name, val) diff --git a/zerver/lib/streams.py b/zerver/lib/streams.py index 67a89bc246..522f4cffed 100644 --- a/zerver/lib/streams.py +++ b/zerver/lib/streams.py @@ -298,7 +298,9 @@ def access_stream_for_send_message( return # All other cases are an error. - raise JsonableError(_("Not authorized to send to stream '{}'").format(stream.name)) + raise JsonableError( + _("Not authorized to send to stream '{stream_name}'").format(stream_name=stream.name) + ) def check_for_exactly_one_stream_arg(stream_id: Optional[int], stream: Optional[str]) -> None: @@ -456,7 +458,9 @@ def check_stream_name_available(realm: Realm, name: str) -> None: check_stream_name(name) try: get_stream(name, realm) - raise JsonableError(_("Stream name '{}' is already taken.").format(name)) + raise JsonableError( + _("Stream name '{stream_name}' is already taken.").format(stream_name=name) + ) except Stream.DoesNotExist: pass @@ -464,7 +468,7 @@ def check_stream_name_available(realm: Realm, name: str) -> None: def access_stream_by_name( user_profile: UserProfile, stream_name: str, allow_realm_admin: bool = False ) -> Tuple[Stream, Optional[Subscription]]: - error = _("Invalid stream name '{}'").format(stream_name) + error = _("Invalid stream name '{stream_name}'").format(stream_name=stream_name) try: stream = get_realm_stream(stream_name, user_profile.realm_id) except Stream.DoesNotExist: @@ -584,7 +588,7 @@ def can_access_stream_history(user_profile: UserProfile, stream: Stream) -> bool if stream.is_history_public_to_subscribers(): # In this case, we check if the user is subscribed. - error = _("Invalid stream name '{}'").format(stream.name) + error = _("Invalid stream name '{stream_name}'").format(stream_name=stream.name) try: access_stream_common(user_profile, stream, error) except JsonableError: @@ -728,8 +732,10 @@ def list_to_streams( if not autocreate: raise JsonableError( - _("Stream(s) ({}) do not exist").format( - ", ".join(stream_dict["name"] for stream_dict in missing_stream_dicts), + _("Stream(s) ({stream_names}) do not exist").format( + stream_names=", ".join( + stream_dict["name"] for stream_dict in missing_stream_dicts + ), ) ) @@ -764,7 +770,9 @@ def access_default_stream_group_by_id(realm: Realm, group_id: int) -> DefaultStr try: return DefaultStreamGroup.objects.get(realm=realm, id=group_id) except DefaultStreamGroup.DoesNotExist: - raise JsonableError(_("Default stream group with id '{}' does not exist.").format(group_id)) + raise JsonableError( + _("Default stream group with id '{group_id}' does not exist.").format(group_id=group_id) + ) def get_stream_by_narrow_operand_access_unchecked(operand: Union[str, int], realm: Realm) -> Stream: diff --git a/zerver/lib/string_validation.py b/zerver/lib/string_validation.py index 22420461cd..1536b0a80f 100644 --- a/zerver/lib/string_validation.py +++ b/zerver/lib/string_validation.py @@ -39,13 +39,17 @@ def check_stream_name(stream_name: str) -> None: if len(stream_name) > Stream.MAX_NAME_LENGTH: raise JsonableError( - _("Stream name too long (limit: {} characters).").format(Stream.MAX_NAME_LENGTH) + _("Stream name too long (limit: {max_length} characters).").format( + max_length=Stream.MAX_NAME_LENGTH + ) ) invalid_character_pos = check_string_is_printable(stream_name) if invalid_character_pos is not None: raise JsonableError( - _("Invalid character in stream name, at position {}!").format(invalid_character_pos) + _("Invalid character in stream name, at position {position}!").format( + position=invalid_character_pos + ) ) @@ -56,5 +60,7 @@ def check_stream_topic(topic: str) -> None: invalid_character_pos = check_string_is_printable(topic) if invalid_character_pos is not None: raise JsonableError( - _("Invalid character in topic, at position {}!").format(invalid_character_pos) + _("Invalid character in topic, at position {position}!").format( + position=invalid_character_pos + ) ) diff --git a/zerver/lib/user_groups.py b/zerver/lib/user_groups.py index 99646e10a9..699cbefac2 100644 --- a/zerver/lib/user_groups.py +++ b/zerver/lib/user_groups.py @@ -63,7 +63,9 @@ def access_user_groups_as_potential_subgroups( valid_group_ids = [group.id for group in user_groups] invalid_group_ids = [group_id for group_id in user_group_ids if group_id not in valid_group_ids] if invalid_group_ids: - raise JsonableError(_("Invalid user group ID: {}").format(invalid_group_ids[0])) + raise JsonableError( + _("Invalid user group ID: {group_id}").format(group_id=invalid_group_ids[0]) + ) return list(user_groups) @@ -81,21 +83,29 @@ def access_user_group_for_setting( user_group = access_user_group_by_id(user_group_id, user_profile, for_read=True) if require_system_group and not user_group.is_system_group: - raise JsonableError(_("'{}' must be a system user group.").format(setting_name)) + raise JsonableError( + _("'{setting_name}' must be a system user group.").format(setting_name=setting_name) + ) if not allow_internet_group and user_group.name == UserGroup.EVERYONE_ON_INTERNET_GROUP_NAME: raise JsonableError( - _("'{}' setting cannot be set to 'role:internet' group.").format(setting_name) + _("'{setting_name}' setting cannot be set to 'role:internet' group.").format( + setting_name=setting_name + ) ) if not allow_owners_group and user_group.name == UserGroup.OWNERS_GROUP_NAME: raise JsonableError( - _("'{}' setting cannot be set to 'role:owners' group.").format(setting_name) + _("'{setting_name}' setting cannot be set to 'role:owners' group.").format( + setting_name=setting_name + ) ) if not allow_nobody_group and user_group.name == UserGroup.NOBODY_GROUP_NAME: raise JsonableError( - _("'{}' setting cannot be set to 'role:nobody' group.").format(setting_name) + _("'{setting_name}' setting cannot be set to 'role:nobody' group.").format( + setting_name=setting_name + ) ) return user_group @@ -104,12 +114,16 @@ def access_user_group_for_setting( def check_user_group_name(group_name: str) -> str: if len(group_name) > UserGroup.MAX_NAME_LENGTH: raise JsonableError( - _("User group name cannot exceed {} characters.").format(UserGroup.MAX_NAME_LENGTH) + _("User group name cannot exceed {max_length} characters.").format( + max_length=UserGroup.MAX_NAME_LENGTH + ) ) for invalid_prefix in UserGroup.INVALID_NAME_PREFIXES: if group_name.startswith(invalid_prefix): - raise JsonableError(_("User group name cannot start with '{}'.").format(invalid_prefix)) + raise JsonableError( + _("User group name cannot start with '{prefix}'.").format(prefix=invalid_prefix) + ) return group_name diff --git a/zerver/lib/users.py b/zerver/lib/users.py index ebcd8e15d8..6e57bd9bf1 100644 --- a/zerver/lib/users.py +++ b/zerver/lib/users.py @@ -92,13 +92,15 @@ def check_valid_bot_config( config_options = {c[1]: c[2] for c in integration.config_options} break if not config_options: - raise JsonableError(_("Invalid integration '{}'.").format(service_name)) + raise JsonableError( + _("Invalid integration '{integration_name}'.").format(integration_name=service_name) + ) missing_keys = set(config_options.keys()) - set(config_data.keys()) if missing_keys: raise JsonableError( - _("Missing configuration parameters: {}").format( - missing_keys, + _("Missing configuration parameters: {keys}").format( + keys=missing_keys, ) ) @@ -106,7 +108,11 @@ def check_valid_bot_config( value = config_data[key] error = validator(key, value) if error is not None: - raise JsonableError(_("Invalid {} value {} ({})").format(key, value, error)) + raise JsonableError( + _("Invalid {key} value {value} ({error})").format( + key=key, value=value, error=error + ) + ) elif bot_type == UserProfile.EMBEDDED_BOT: try: @@ -229,12 +235,12 @@ def user_ids_to_users(user_ids: Sequence[int], realm: Realm) -> List[UserProfile found_user_ids = user_profiles_by_id.keys() missed_user_ids = [user_id for user_id in user_ids if user_id not in found_user_ids] if missed_user_ids: - raise JsonableError(_("Invalid user ID: {}").format(missed_user_ids[0])) + raise JsonableError(_("Invalid user ID: {user_id}").format(user_id=missed_user_ids[0])) user_profiles = list(user_profiles_by_id.values()) for user_profile in user_profiles: if user_profile.realm != realm: - raise JsonableError(_("Invalid user ID: {}").format(user_profile.id)) + raise JsonableError(_("Invalid user ID: {user_id}").format(user_id=user_profile.id)) return user_profiles diff --git a/zerver/lib/validator.py b/zerver/lib/validator.py index 977130f83b..08d4977815 100644 --- a/zerver/lib/validator.py +++ b/zerver/lib/validator.py @@ -314,7 +314,7 @@ def check_dict( delta_keys = set(val.keys()) - required_keys_set - optional_keys_set if len(delta_keys) != 0: raise ValidationError( - _("Unexpected arguments: {}").format(", ".join(list(delta_keys))) + _("Unexpected arguments: {keys}").format(keys=", ".join(list(delta_keys))) ) return cast(Dict[str, ResultT], val) diff --git a/zerver/lib/webhooks/common.py b/zerver/lib/webhooks/common.py index 17e2b44095..3cc2851734 100644 --- a/zerver/lib/webhooks/common.py +++ b/zerver/lib/webhooks/common.py @@ -228,4 +228,6 @@ def unix_milliseconds_to_timestamp(milliseconds: Any, webhook: str) -> datetime: seconds = milliseconds / 1000 return timestamp_to_datetime(seconds) except (ValueError, TypeError): - raise JsonableError(_("The {} webhook expects time in milliseconds.").format(webhook)) + raise JsonableError( + _("The {webhook} webhook expects time in milliseconds.").format(webhook=webhook) + ) diff --git a/zerver/lib/zcommand.py b/zerver/lib/zcommand.py index 8041f1e5da..e29335499b 100644 --- a/zerver/lib/zcommand.py +++ b/zerver/lib/zcommand.py @@ -76,4 +76,4 @@ def process_zcommands(content: str, user_profile: UserProfile) -> Dict[str, Any] setting_value=False, ) ) - raise JsonableError(_("No such command: {}").format(command)) + raise JsonableError(_("No such command: {command}").format(command=command)) diff --git a/zerver/models.py b/zerver/models.py index edaad57610..45860f6562 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -1230,9 +1230,11 @@ def filter_pattern_validator(value: str) -> Pattern[str]: except re2.error as e: if len(e.args) >= 1: if isinstance(e.args[0], str): # nocoverage - raise ValidationError(_("Bad regular expression: {}").format(e.args[0])) + raise ValidationError(_("Bad regular expression: {regex}").format(regex=e.args[0])) if isinstance(e.args[0], bytes): - raise ValidationError(_("Bad regular expression: {}").format(e.args[0].decode())) + raise ValidationError( + _("Bad regular expression: {regex}").format(regex=e.args[0].decode()) + ) raise ValidationError(_("Unknown regular expression error")) # nocoverage return regex @@ -4697,13 +4699,15 @@ def check_valid_user_ids(realm_id: int, val: object, allow_deactivated: bool = F try: user_profile = get_user_profile_by_id_in_realm(user_id, realm) except UserProfile.DoesNotExist: - raise ValidationError(_("Invalid user ID: {}").format(user_id)) + raise ValidationError(_("Invalid user ID: {user_id}").format(user_id=user_id)) if not allow_deactivated and not user_profile.is_active: - raise ValidationError(_("User with ID {} is deactivated").format(user_id)) + raise ValidationError( + _("User with ID {user_id} is deactivated").format(user_id=user_id) + ) if user_profile.is_bot: - raise ValidationError(_("User with ID {} is a bot").format(user_id)) + raise ValidationError(_("User with ID {user_id} is a bot").format(user_id=user_id)) return user_ids diff --git a/zerver/views/events_register.py b/zerver/views/events_register.py index 5800fe5f81..4f703bf4f3 100644 --- a/zerver/views/events_register.py +++ b/zerver/views/events_register.py @@ -105,11 +105,13 @@ def events_register_backend( # These parameters must be false for anonymous requests. if client_gravatar: raise JsonableError( - _("Invalid '{}' parameter for anonymous request").format("client_gravatar") + _("Invalid '{key}' parameter for anonymous request").format(key="client_gravatar") ) if include_subscribers: raise JsonableError( - _("Invalid '{}' parameter for anonymous request").format("include_subscribers") + _("Invalid '{key}' parameter for anonymous request").format( + key="include_subscribers" + ) ) # Language set by spectator to be passed down to clients as user_settings. diff --git a/zerver/views/hotspots.py b/zerver/views/hotspots.py index bb00daccc3..11c24a5bd3 100644 --- a/zerver/views/hotspots.py +++ b/zerver/views/hotspots.py @@ -16,6 +16,6 @@ def mark_hotspot_as_read( request: HttpRequest, user: UserProfile, hotspot: str = REQ() ) -> HttpResponse: if hotspot not in ALL_HOTSPOTS: - raise JsonableError(_("Unknown hotspot: {}").format(hotspot)) + raise JsonableError(_("Unknown hotspot: {hotspot}").format(hotspot=hotspot)) do_mark_hotspot_as_read(user, hotspot) return json_success(request) diff --git a/zerver/views/invite.py b/zerver/views/invite.py index e7088e862d..88c69be101 100644 --- a/zerver/views/invite.py +++ b/zerver/views/invite.py @@ -79,7 +79,9 @@ def invite_users_backend( (stream, sub) = access_stream_by_id(user_profile, stream_id) except JsonableError: raise JsonableError( - _("Stream does not exist with id: {}. No invites were sent.").format(stream_id) + _("Stream does not exist with id: {stream_id}. No invites were sent.").format( + stream_id=stream_id + ) ) streams.append(stream) @@ -204,7 +206,11 @@ def generate_multiuse_invite_backend( try: (stream, sub) = access_stream_by_id(user_profile, stream_id) except JsonableError: - raise JsonableError(_("Invalid stream ID {}. No invites were sent.").format(stream_id)) + raise JsonableError( + _("Invalid stream ID {stream_id}. No invites were sent.").format( + stream_id=stream_id + ) + ) streams.append(stream) invite_link = do_create_multiuse_invite_link( diff --git a/zerver/views/message_fetch.py b/zerver/views/message_fetch.py index 0a5b6a0812..0752feb82a 100644 --- a/zerver/views/message_fetch.py +++ b/zerver/views/message_fetch.py @@ -96,8 +96,8 @@ def get_messages_backend( anchor = parse_anchor_value(anchor_val, use_first_unread_anchor_val) if num_before + num_after > MAX_MESSAGES_PER_FETCH: raise JsonableError( - _("Too many messages requested (maximum {}).").format( - MAX_MESSAGES_PER_FETCH, + _("Too many messages requested (maximum {max_messages}).").format( + max_messages=MAX_MESSAGES_PER_FETCH, ) ) if num_before > 0 and num_after > 0 and not include_anchor: diff --git a/zerver/views/message_flags.py b/zerver/views/message_flags.py index 29f6ec1f5d..d366fa899d 100644 --- a/zerver/views/message_flags.py +++ b/zerver/views/message_flags.py @@ -166,7 +166,7 @@ def mark_topic_as_read( ) if not topic_exists: - raise JsonableError(_("No such topic '{}'").format(topic_name)) + raise JsonableError(_("No such topic '{topic}'").format(topic=topic_name)) count = do_mark_stream_messages_as_read(user_profile, stream.recipient_id, topic_name) diff --git a/zerver/views/presence.py b/zerver/views/presence.py index 0773ba0c8b..468f509717 100644 --- a/zerver/views/presence.py +++ b/zerver/views/presence.py @@ -143,7 +143,7 @@ def update_active_status_backend( ) -> HttpResponse: status_val = UserPresence.status_from_string(status) if status_val is None: - raise JsonableError(_("Invalid status: {}").format(status)) + raise JsonableError(_("Invalid status: {status}").format(status=status)) elif user_profile.presence_enabled: client = RequestNotes.get_notes(request).client assert client is not None diff --git a/zerver/views/realm.py b/zerver/views/realm.py index 066cf21491..77619cfea1 100644 --- a/zerver/views/realm.py +++ b/zerver/views/realm.py @@ -157,7 +157,7 @@ def update_realm( # Additional validation/error checking beyond types go here, so # the entire request can succeed or fail atomically. if default_language is not None and default_language not in get_available_language_codes(): - raise JsonableError(_("Invalid language '{}'").format(default_language)) + raise JsonableError(_("Invalid language '{language}'").format(language=default_language)) if authentication_methods is not None: if not user_profile.is_realm_owner: raise OrganizationOwnerRequiredError @@ -166,11 +166,17 @@ def update_realm( if video_chat_provider is not None and video_chat_provider not in { p["id"] for p in Realm.VIDEO_CHAT_PROVIDERS.values() }: - raise JsonableError(_("Invalid video_chat_provider {}").format(video_chat_provider)) + raise JsonableError( + _("Invalid video_chat_provider {video_chat_provider}").format( + video_chat_provider=video_chat_provider + ) + ) if giphy_rating is not None and giphy_rating not in { p["id"] for p in Realm.GIPHY_RATING_OPTIONS.values() }: - raise JsonableError(_("Invalid giphy_rating {}").format(giphy_rating)) + raise JsonableError( + _("Invalid giphy_rating {giphy_rating}").format(giphy_rating=giphy_rating) + ) message_retention_days: Optional[int] = None if message_retention_days_raw is not None: diff --git a/zerver/views/realm_domains.py b/zerver/views/realm_domains.py index b4bef5bac1..c27de2cdbc 100644 --- a/zerver/views/realm_domains.py +++ b/zerver/views/realm_domains.py @@ -33,7 +33,7 @@ def create_realm_domain( try: validate_domain(domain) except ValidationError as e: - raise JsonableError(_("Invalid domain: {}").format(e.messages[0])) + raise JsonableError(_("Invalid domain: {error}").format(error=e.messages[0])) if RealmDomain.objects.filter(realm=user_profile.realm, domain=domain).exists(): raise JsonableError( _("The domain {domain} is already a part of your organization.").format(domain=domain) diff --git a/zerver/views/realm_emoji.py b/zerver/views/realm_emoji.py index e7389a0a2f..c0bc66b0a7 100644 --- a/zerver/views/realm_emoji.py +++ b/zerver/views/realm_emoji.py @@ -45,8 +45,8 @@ def upload_emoji( assert emoji_file.size is not None if (settings.MAX_EMOJI_FILE_SIZE_MIB * 1024 * 1024) < emoji_file.size: raise JsonableError( - _("Uploaded file is larger than the allowed limit of {} MiB").format( - settings.MAX_EMOJI_FILE_SIZE_MIB, + _("Uploaded file is larger than the allowed limit of {max_size} MiB").format( + max_size=settings.MAX_EMOJI_FILE_SIZE_MIB, ) ) @@ -58,7 +58,9 @@ def delete_emoji(request: HttpRequest, user_profile: UserProfile, emoji_name: st if not RealmEmoji.objects.filter( realm=user_profile.realm, name=emoji_name, deactivated=False ).exists(): - raise ResourceNotFoundError(_("Emoji '{}' does not exist").format(emoji_name)) + raise ResourceNotFoundError( + _("Emoji '{emoji_name}' does not exist").format(emoji_name=emoji_name) + ) check_remove_custom_emoji(user_profile, emoji_name) do_remove_realm_emoji(user_profile.realm, emoji_name, acting_user=user_profile) return json_success(request) diff --git a/zerver/views/realm_icon.py b/zerver/views/realm_icon.py index ed86606f09..683dde730c 100644 --- a/zerver/views/realm_icon.py +++ b/zerver/views/realm_icon.py @@ -24,8 +24,8 @@ def upload_icon(request: HttpRequest, user_profile: UserProfile) -> HttpResponse assert icon_file.size is not None if (settings.MAX_ICON_FILE_SIZE_MIB * 1024 * 1024) < icon_file.size: raise JsonableError( - _("Uploaded file is larger than the allowed limit of {} MiB").format( - settings.MAX_ICON_FILE_SIZE_MIB, + _("Uploaded file is larger than the allowed limit of {max_size} MiB").format( + max_size=settings.MAX_ICON_FILE_SIZE_MIB, ) ) upload_icon_image(icon_file, user_profile) diff --git a/zerver/views/realm_logo.py b/zerver/views/realm_logo.py index 6339062024..0a712ab172 100644 --- a/zerver/views/realm_logo.py +++ b/zerver/views/realm_logo.py @@ -30,8 +30,8 @@ def upload_logo( assert logo_file.size is not None if (settings.MAX_LOGO_FILE_SIZE_MIB * 1024 * 1024) < logo_file.size: raise JsonableError( - _("Uploaded file is larger than the allowed limit of {} MiB").format( - settings.MAX_LOGO_FILE_SIZE_MIB, + _("Uploaded file is larger than the allowed limit of {max_size} MiB").format( + max_size=settings.MAX_LOGO_FILE_SIZE_MIB, ) ) upload_logo_image(logo_file, user_profile, night) diff --git a/zerver/views/streams.py b/zerver/views/streams.py index 5322acfb1b..534a70ed70 100644 --- a/zerver/views/streams.py +++ b/zerver/views/streams.py @@ -1052,11 +1052,15 @@ def update_subscription_properties_backend( value = change["value"] if property not in property_converters: - raise JsonableError(_("Unknown subscription property: {}").format(property)) + raise JsonableError( + _("Unknown subscription property: {property}").format(property=property) + ) (stream, sub) = access_stream_by_id(user_profile, stream_id) if sub is None: - raise JsonableError(_("Not subscribed to stream id {}").format(stream_id)) + raise JsonableError( + _("Not subscribed to stream id {stream_id}").format(stream_id=stream_id) + ) try: value = property_converters[property](property, value) diff --git a/zerver/views/upload.py b/zerver/views/upload.py index b39fec0d41..fbe5caaf25 100644 --- a/zerver/views/upload.py +++ b/zerver/views/upload.py @@ -275,8 +275,8 @@ def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> Http assert file_size is not None if settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024 < file_size: raise JsonableError( - _("Uploaded file is larger than the allowed limit of {} MiB").format( - settings.MAX_FILE_UPLOAD_SIZE, + _("Uploaded file is larger than the allowed limit of {max_size} MiB").format( + max_size=settings.MAX_FILE_UPLOAD_SIZE, ) ) check_upload_within_quota(user_profile.realm, file_size) diff --git a/zerver/views/user_groups.py b/zerver/views/user_groups.py index b37de2d481..0b1d103aad 100644 --- a/zerver/views/user_groups.py +++ b/zerver/views/user_groups.py @@ -265,7 +265,9 @@ def remove_members_from_group_backend( group_member_ids = get_user_group_direct_member_ids(user_group) for member in members: if member not in group_member_ids: - raise JsonableError(_("There is no member '{}' in this user group").format(member)) + raise JsonableError( + _("There is no member '{user_id}' in this user group").format(user_id=member) + ) user_profile_ids = [user.id for user in user_profiles] remove_members_from_user_group(user_group, user_profile_ids, acting_user=user_profile) diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py index 7073a8151f..90bb7244c3 100644 --- a/zerver/views/user_settings.py +++ b/zerver/views/user_settings.py @@ -130,7 +130,11 @@ def check_settings_values( and notification_sound not in get_available_notification_sounds() and notification_sound != "none" ): - raise JsonableError(_("Invalid notification sound '{}'").format(notification_sound)) + raise JsonableError( + _("Invalid notification sound '{notification_sound}'").format( + notification_sound=notification_sound + ) + ) if email_notifications_batching_period_seconds is not None and ( email_notifications_batching_period_seconds <= 0 @@ -138,8 +142,8 @@ def check_settings_values( ): # We set a limit of one week for the batching period raise JsonableError( - _("Invalid email batching period: {} seconds").format( - email_notifications_batching_period_seconds + _("Invalid email batching period: {seconds} seconds").format( + seconds=email_notifications_batching_period_seconds ) ) @@ -275,8 +279,8 @@ def json_change_settings( assert e.secs_to_freedom is not None secs_to_freedom = int(e.secs_to_freedom) raise JsonableError( - _("You're making too many attempts! Try again in {} seconds.").format( - secs_to_freedom + _("You're making too many attempts! Try again in {seconds} seconds.").format( + seconds=secs_to_freedom ), ) @@ -364,8 +368,8 @@ def set_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> HttpR assert user_file.size is not None if (settings.MAX_AVATAR_FILE_SIZE_MIB * 1024 * 1024) < user_file.size: raise JsonableError( - _("Uploaded file is larger than the allowed limit of {} MiB").format( - settings.MAX_AVATAR_FILE_SIZE_MIB, + _("Uploaded file is larger than the allowed limit of {max_size} MiB").format( + max_size=settings.MAX_AVATAR_FILE_SIZE_MIB, ) ) upload_avatar_image(user_file, user_profile, user_profile) diff --git a/zerver/views/users.py b/zerver/views/users.py index 8fd247fcb8..1bbc4893b5 100644 --- a/zerver/views/users.py +++ b/zerver/views/users.py @@ -709,7 +709,7 @@ def create_user_backend( try: get_user_by_delivery_email(email, user_profile.realm) - raise JsonableError(_("Email '{}' already in use").format(email)) + raise JsonableError(_("Email '{email}' already in use").format(email=email)) except UserProfile.DoesNotExist: pass diff --git a/zerver/webhooks/wordpress/view.py b/zerver/webhooks/wordpress/view.py index bdce82434d..799e331413 100644 --- a/zerver/webhooks/wordpress/view.py +++ b/zerver/webhooks/wordpress/view.py @@ -53,7 +53,7 @@ def api_wordpress_webhook( data = WP_LOGIN_TEMPLATE.format(name=user_login) else: - raise JsonableError(_("Unknown WordPress webhook action: {}").format(hook)) + raise JsonableError(_("Unknown WordPress webhook action: {hook}").format(hook=hook)) topic = "WordPress notification" diff --git a/zilencer/views.py b/zilencer/views.py index f4859f6a45..6174549ad3 100644 --- a/zilencer/views.py +++ b/zilencer/views.py @@ -106,7 +106,7 @@ def register_remote_server( url_validator = URLValidator() url_validator("http://" + hostname) except ValidationError: - raise JsonableError(_("{} is not a valid hostname").format(hostname)) + raise JsonableError(_("{hostname} is not a valid hostname").format(hostname=hostname)) try: validate_email(contact_email) @@ -370,7 +370,7 @@ def validate_incoming_table_data( last_id = get_last_id_from_server(server, model) for row in rows: if is_count_stat and row["property"] not in COUNT_STATS: - raise JsonableError(_("Invalid property {}").format(row["property"])) + raise JsonableError(_("Invalid property {property}").format(property=row["property"])) if row["id"] <= last_id: raise JsonableError(_("Data is out of order.")) last_id = row["id"]