python: Convert percent formatting to .format for translated strings.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-06-15 14:22:24 -07:00 committed by Tim Abbott
parent eda396376c
commit f364d06fb5
37 changed files with 212 additions and 163 deletions

View File

@ -243,7 +243,7 @@ def get_chart_data(request: HttpRequest, user_profile: UserProfile, chart_name:
labels_sort_function = None labels_sort_function = None
include_empty_subgroups = True include_empty_subgroups = True
else: else:
raise JsonableError(_("Unknown chart name: %s") % (chart_name,)) raise JsonableError(_("Unknown chart name: {}").format(chart_name))
# Most likely someone using our API endpoint. The /stats page does not # Most likely someone using our API endpoint. The /stats page does not
# pass a start or end in its requests. # pass a start or end in its requests.
@ -252,8 +252,9 @@ def get_chart_data(request: HttpRequest, user_profile: UserProfile, chart_name:
if end is not None: if end is not None:
end = convert_to_UTC(end) end = convert_to_UTC(end)
if start is not None and end is not None and start > end: if start is not None and end is not None and start > end:
raise JsonableError(_("Start time is later than end time. Start: %(start)s, End: %(end)s") % raise JsonableError(_("Start time is later than end time. Start: {start}, End: {end}").format(
{'start': start, 'end': end}) start=start, end=end,
))
if realm is None: if realm is None:
# Note that this value is invalid for Remote tables; be # Note that this value is invalid for Remote tables; be

View File

@ -135,7 +135,9 @@ def renewal_amount(plan: CustomerPlan, event_time: datetime) -> int: # nocovera
class BillingError(Exception): class BillingError(Exception):
# error messages # error messages
CONTACT_SUPPORT = _("Something went wrong. Please contact %s.") % (settings.ZULIP_ADMINISTRATOR,) CONTACT_SUPPORT = _("Something went wrong. Please contact {email}.").format(
email=settings.ZULIP_ADMINISTRATOR,
)
TRY_RELOADING = _("Something went wrong. Please reload the page.") TRY_RELOADING = _("Something went wrong. Please reload the page.")
# description is used only for tests # description is used only for tests

View File

@ -1,6 +1,6 @@
import logging import logging
from decimal import Decimal from decimal import Decimal
from typing import Any, Dict, Optional, Union, cast from typing import Any, Dict, Optional, Union
import stripe import stripe
from django.conf import settings from django.conf import settings
@ -85,14 +85,17 @@ def payment_method_string(stripe_customer: stripe.Customer) -> str:
if stripe_source is None: # nocoverage if stripe_source is None: # nocoverage
return _("No payment method on file") return _("No payment method on file")
if stripe_source.object == "card": if stripe_source.object == "card":
return _("%(brand)s ending in %(last4)s") % { assert isinstance(stripe_source, stripe.Card)
'brand': cast(stripe.Card, stripe_source).brand, return _("{brand} ending in {last4}").format(
'last4': cast(stripe.Card, stripe_source).last4} brand=stripe_source.brand, last4=stripe_source.last4,
)
# There might be one-off stuff we do for a particular customer that # There might be one-off stuff we do for a particular customer that
# would land them here. E.g. by default we don't support ACH for # would land them here. E.g. by default we don't support ACH for
# automatic payments, but in theory we could add it for a customer via # automatic payments, but in theory we could add it for a customer via
# the Stripe dashboard. # the Stripe dashboard.
return _("Unknown payment method. Please contact %s.") % (settings.ZULIP_ADMINISTRATOR,) # nocoverage return _("Unknown payment method. Please contact {email}.").format(
email=settings.ZULIP_ADMINISTRATOR,
) # nocoverage
@has_request_variables @has_request_variables
def upgrade(request: HttpRequest, user: UserProfile, def upgrade(request: HttpRequest, user: UserProfile,

View File

@ -171,7 +171,7 @@ SPLIT_BOUNDARY_REGEX = re.compile(fr'[{SPLIT_BOUNDARY}]')
# Regexes which check capitalization in sentences. # Regexes which check capitalization in sentences.
DISALLOWED_REGEXES = [re.compile(regex) for regex in [ DISALLOWED_REGEXES = [re.compile(regex) for regex in [
r'^[a-z]', # Checks if the sentence starts with a lower case character. r'^[a-z](?!\})', # Checks if the sentence starts with a lower case character.
r'^[A-Z][a-z]+[\sa-z0-9]+[A-Z]', # Checks if an upper case character exists r'^[A-Z][a-z]+[\sa-z0-9]+[A-Z]', # Checks if an upper case character exists
# after a lower case character when the first character is in upper case. # after a lower case character when the first character is in upper case.
]] ]]

View File

@ -81,6 +81,14 @@ rules:
severity: ERROR severity: ERROR
message: "Do not write a SQL injection vulnerability please" message: "Do not write a SQL injection vulnerability please"
- id: translated-format
languages: [python]
pattern-either:
- pattern: django.utils.translation.ugettext(... .format(...))
- pattern: django.utils.translation.ugettext(f"...")
severity: ERROR
message: "Format strings after translation, not before"
- id: mutable-default-type - id: mutable-default-type
languages: [python] languages: [python]
pattern-either: pattern-either:
@ -122,5 +130,6 @@ rules:
pattern-either: pattern-either:
- pattern: '"..." % ...' - pattern: '"..." % ...'
- pattern: '("...") % ...' - pattern: '("...") % ...'
- pattern: django.utils.translation.ugettext(...) % ...
severity: ERROR severity: ERROR
message: "Prefer f-strings or .format for string formatting" message: "Prefer f-strings or .format for string formatting"

View File

@ -1948,7 +1948,7 @@ def validate_recipient_user_profiles(user_profiles: Sequence[UserProfile],
for user_profile in user_profiles: for user_profile in user_profiles:
if (not user_profile.is_active and not user_profile.is_mirror_dummy and if (not user_profile.is_active and not user_profile.is_mirror_dummy and
not allow_deactivated) or user_profile.realm.deactivated: not allow_deactivated) or user_profile.realm.deactivated:
raise ValidationError(_("'%s' is no longer using Zulip.") % (user_profile.email,)) raise ValidationError(_("'{email}' is no longer using Zulip.").format(email=user_profile.email))
recipient_profiles_map[user_profile.id] = user_profile recipient_profiles_map[user_profile.id] = user_profile
if not is_cross_realm_bot_email(user_profile.email): if not is_cross_realm_bot_email(user_profile.email):
realms.add(user_profile.realm_id) realms.add(user_profile.realm_id)
@ -2132,14 +2132,16 @@ def check_schedule_message(sender: UserProfile, client: Client,
def check_default_stream_group_name(group_name: str) -> None: def check_default_stream_group_name(group_name: str) -> None:
if group_name.strip() == "": if group_name.strip() == "":
raise JsonableError(_("Invalid default stream group name '%s'") % (group_name,)) raise JsonableError(_("Invalid default stream group name '{}'").format(group_name))
if len(group_name) > DefaultStreamGroup.MAX_NAME_LENGTH: if len(group_name) > DefaultStreamGroup.MAX_NAME_LENGTH:
raise JsonableError(_("Default stream group name too long (limit: %s characters)") raise JsonableError(_("Default stream group name too long (limit: {} characters)").format(
% (DefaultStreamGroup.MAX_NAME_LENGTH,)) DefaultStreamGroup.MAX_NAME_LENGTH,
))
for i in group_name: for i in group_name:
if ord(i) == 0: if ord(i) == 0:
raise JsonableError(_("Default stream group name '%s' contains NULL (0x00) characters.") raise JsonableError(_("Default stream group name '{}' contains NULL (0x00) characters.").format(
% (group_name,)) group_name,
))
def send_rate_limited_pm_notification_to_bot_owner(sender: UserProfile, def send_rate_limited_pm_notification_to_bot_owner(sender: UserProfile,
realm: Realm, realm: Realm,
@ -2194,19 +2196,19 @@ def send_pm_if_empty_stream(stream: Optional[Stream],
} }
if stream is None: if stream is None:
if stream_id is not None: if stream_id is not None:
content = _("Your bot `%(bot_identity)s` tried to send a message to stream ID " content = _("Your bot `{bot_identity}` tried to send a message to stream ID "
"%(stream_id)s, but there is no stream with that ID.") % arg_dict "{stream_id}, but there is no stream with that ID.").format(**arg_dict)
else: else:
assert(stream_name is not None) assert(stream_name is not None)
content = _("Your bot `%(bot_identity)s` tried to send a message to stream " content = _("Your bot `{bot_identity}` tried to send a message to stream "
"#**%(stream_name)s**, but that stream does not exist. " "#**{stream_name}**, but that stream does not exist. "
"Click [here](#streams/new) to create it.") % arg_dict "Click [here](#streams/new) to create it.").format(**arg_dict)
else: else:
if num_subscribers_for_stream_id(stream.id) > 0: if num_subscribers_for_stream_id(stream.id) > 0:
return return
content = _("Your bot `%(bot_identity)s` tried to send a message to " content = _("Your bot `{bot_identity}` tried to send a message to "
"stream #**%(stream_name)s**. The stream exists but " "stream #**{stream_name}**. The stream exists but "
"does not have any subscribers.") % arg_dict "does not have any subscribers.").format(**arg_dict)
send_rate_limited_pm_notification_to_bot_owner(sender, realm, content) send_rate_limited_pm_notification_to_bot_owner(sender, realm, content)
@ -2349,7 +2351,9 @@ def check_message(sender: UserProfile, client: Client, addressee: Addressee,
error_msg = check_widget_content(widget_content) error_msg = check_widget_content(widget_content)
if error_msg: if error_msg:
raise JsonableError(_('Widgets: %s') % (error_msg,)) raise JsonableError(_('Widgets: {error_msg}').format(
error_msg=error_msg,
))
return {'message': message, 'stream': stream, 'local_id': local_id, return {'message': message, 'stream': stream, 'local_id': local_id,
'sender_queue_id': sender_queue_id, 'realm': realm, 'sender_queue_id': sender_queue_id, 'realm': realm,
@ -3583,12 +3587,13 @@ def do_rename_stream(stream: Stream,
sender, sender,
stream, stream,
Realm.STREAM_EVENTS_NOTIFICATION_TOPIC, Realm.STREAM_EVENTS_NOTIFICATION_TOPIC,
_('@_**%(user_name)s|%(user_id)d** renamed stream **%(old_stream_name)s** to ' _('@_**{user_name}|{user_id}** renamed stream **{old_stream_name}** to '
'**%(new_stream_name)s**.') % { '**{new_stream_name}**.').format(
'user_name': user_profile.full_name, user_name=user_profile.full_name,
'user_id': user_profile.id, user_id=user_profile.id,
'old_stream_name': old_name, old_stream_name=old_name,
'new_stream_name': new_name}, new_stream_name=new_name,
),
) )
# Even though the token doesn't change, the web client needs to update the # Even though the token doesn't change, the web client needs to update the
# email forwarding address to display the correctly-escaped new name. # email forwarding address to display the correctly-escaped new name.
@ -3734,7 +3739,7 @@ def lookup_default_stream_groups(default_stream_group_names: List[str],
default_stream_group = DefaultStreamGroup.objects.get( default_stream_group = DefaultStreamGroup.objects.get(
name=group_name, realm=realm) name=group_name, realm=realm)
except DefaultStreamGroup.DoesNotExist: except DefaultStreamGroup.DoesNotExist:
raise JsonableError(_('Invalid default stream group %s') % (group_name,)) raise JsonableError(_('Invalid default stream group {}').format(group_name))
default_stream_groups.append(default_stream_group) default_stream_groups.append(default_stream_group)
return default_stream_groups return default_stream_groups
@ -3771,15 +3776,16 @@ def do_create_default_stream_group(realm: Realm, group_name: str,
for stream in streams: for stream in streams:
if stream in default_streams: if stream in default_streams:
raise JsonableError(_( raise JsonableError(_(
"'%(stream_name)s' is a default stream and cannot be added to '%(group_name)s'") "'{stream_name}' is a default stream and cannot be added to '{group_name}'",
% {'stream_name': stream.name, 'group_name': group_name}) ).format(stream_name=stream.name, group_name=group_name))
check_default_stream_group_name(group_name) check_default_stream_group_name(group_name)
(group, created) = DefaultStreamGroup.objects.get_or_create( (group, created) = DefaultStreamGroup.objects.get_or_create(
name=group_name, realm=realm, description=description) name=group_name, realm=realm, description=description)
if not created: if not created:
raise JsonableError(_("Default stream group '%(group_name)s' already exists") raise JsonableError(_(
% {'group_name': group_name}) "Default stream group '{group_name}' already exists",
).format(group_name=group_name))
group.streams.set(streams) group.streams.set(streams)
notify_default_stream_groups(realm) notify_default_stream_groups(realm)
@ -3790,12 +3796,12 @@ def do_add_streams_to_default_stream_group(realm: Realm, group: DefaultStreamGro
for stream in streams: for stream in streams:
if stream in default_streams: if stream in default_streams:
raise JsonableError(_( raise JsonableError(_(
"'%(stream_name)s' is a default stream and cannot be added to '%(group_name)s'") "'{stream_name}' is a default stream and cannot be added to '{group_name}'",
% {'stream_name': stream.name, 'group_name': group.name}) ).format(stream_name=stream.name, group_name=group.name))
if stream in group.streams.all(): if stream in group.streams.all():
raise JsonableError(_( raise JsonableError(_(
"Stream '%(stream_name)s' is already present in default stream group '%(group_name)s'") "Stream '{stream_name}' is already present in default stream group '{group_name}'",
% {'stream_name': stream.name, 'group_name': group.name}) ).format(stream_name=stream.name, group_name=group.name))
group.streams.add(stream) group.streams.add(stream)
group.save() group.save()
@ -3806,8 +3812,8 @@ def do_remove_streams_from_default_stream_group(realm: Realm, group: DefaultStre
for stream in streams: for stream in streams:
if stream not in group.streams.all(): if stream not in group.streams.all():
raise JsonableError(_( raise JsonableError(_(
"Stream '%(stream_name)s' is not present in default stream group '%(group_name)s'") "Stream '{stream_name}' is not present in default stream group '{group_name}'",
% {'stream_name': stream.name, 'group_name': group.name}) ).format(stream_name=stream.name, group_name=group.name))
group.streams.remove(stream) group.streams.remove(stream)
group.save() group.save()
@ -3816,10 +3822,10 @@ def do_remove_streams_from_default_stream_group(realm: Realm, group: DefaultStre
def do_change_default_stream_group_name(realm: Realm, group: DefaultStreamGroup, def do_change_default_stream_group_name(realm: Realm, group: DefaultStreamGroup,
new_group_name: str) -> None: new_group_name: str) -> None:
if group.name == new_group_name: if group.name == new_group_name:
raise JsonableError(_("This default stream group is already named '%s'") % (new_group_name,)) raise JsonableError(_("This default stream group is already named '{}'").format(new_group_name))
if DefaultStreamGroup.objects.filter(name=new_group_name, realm=realm).exists(): if DefaultStreamGroup.objects.filter(name=new_group_name, realm=realm).exists():
raise JsonableError(_("Default stream group '%s' already exists") % (new_group_name,)) raise JsonableError(_("Default stream group '{}' already exists").format(new_group_name))
group.name = new_group_name group.name = new_group_name
group.save() group.save()
@ -4172,9 +4178,9 @@ def do_update_message_flags(user_profile: UserProfile,
valid_flags = [item for item in UserMessage.flags valid_flags = [item for item in UserMessage.flags
if item not in UserMessage.NON_API_FLAGS] if item not in UserMessage.NON_API_FLAGS]
if flag not in valid_flags: if flag not in valid_flags:
raise JsonableError(_("Invalid flag: '%s'") % (flag,)) raise JsonableError(_("Invalid flag: '{}'").format(flag))
if flag in UserMessage.NON_EDITABLE_FLAGS: if flag in UserMessage.NON_EDITABLE_FLAGS:
raise JsonableError(_("Flag not editable: '%s'") % (flag,)) raise JsonableError(_("Flag not editable: '{}'").format(flag))
flagattr = getattr(UserMessage.flags, flag) flagattr = getattr(UserMessage.flags, flag)
msgs = UserMessage.objects.filter(user_profile=user_profile, msgs = UserMessage.objects.filter(user_profile=user_profile,
@ -4250,15 +4256,19 @@ def notify_topic_moved_streams(user_profile: UserProfile,
if send_notification_to_new_thread: if send_notification_to_new_thread:
internal_send_stream_message( internal_send_stream_message(
new_stream.realm, sender, new_stream, new_topic, new_stream.realm, sender, new_stream, new_topic,
_("This topic was moved here from %(old_location)s by %(user)s") _("This topic was moved here from {old_location} by {user}").format(
% dict(old_location=old_topic_link, user=user_mention)) old_location=old_topic_link, user=user_mention,
),
)
if send_notification_to_old_thread: if send_notification_to_old_thread:
# Send a notification to the old stream that the topic was moved. # Send a notification to the old stream that the topic was moved.
internal_send_stream_message( internal_send_stream_message(
old_stream.realm, sender, old_stream, old_topic, old_stream.realm, sender, old_stream, old_topic,
_("This topic was moved by %(user)s to %(new_location)s") _("This topic was moved by {user} to {new_location}").format(
% dict(user=user_mention, new_location=new_topic_link)) user=user_mention, new_location=new_topic_link,
),
)
def get_user_info_for_message_updates(message_id: int) -> MessageUpdateUserInfoResult: def get_user_info_for_message_updates(message_id: int) -> MessageUpdateUserInfoResult:
@ -4992,8 +5002,8 @@ def estimate_recent_invites(realms: Iterable[Realm], *, days: int) -> int:
def check_invite_limit(realm: Realm, num_invitees: int) -> None: def check_invite_limit(realm: Realm, num_invitees: int) -> None:
'''Discourage using invitation emails as a vector for carrying spam.''' '''Discourage using invitation emails as a vector for carrying spam.'''
msg = _("You do not have enough remaining invites. " msg = _("You do not have enough remaining invites. "
"Please contact %s to have your limit raised. " "Please contact {email} to have your limit raised. "
"No invitations were sent.") % (settings.ZULIP_ADMINISTRATOR,) "No invitations were sent.").format(email=settings.ZULIP_ADMINISTRATOR)
if not settings.OPEN_REALM_CREATION: if not settings.OPEN_REALM_CREATION:
return return
@ -5617,7 +5627,7 @@ def check_add_user_group(realm: Realm, name: str, initial_members: List[UserProf
user_group = create_user_group(name, initial_members, realm, description=description) user_group = create_user_group(name, initial_members, realm, description=description)
do_send_create_user_group_event(user_group, initial_members) do_send_create_user_group_event(user_group, initial_members)
except django.db.utils.IntegrityError: except django.db.utils.IntegrityError:
raise JsonableError(_("User group '%s' already exists.") % (name,)) raise JsonableError(_("User group '{}' already exists.").format(name))
def do_send_user_group_update_event(user_group: UserGroup, data: Dict[str, Any]) -> None: def do_send_user_group_update_event(user_group: UserGroup, data: Dict[str, Any]) -> None:
event = dict(type="user_group", op='update', group_id=user_group.id, data=data) event = dict(type="user_group", op='update', group_id=user_group.id, data=data)
@ -5628,7 +5638,7 @@ def do_update_user_group_name(user_group: UserGroup, name: str) -> None:
user_group.name = name user_group.name = name
user_group.save(update_fields=['name']) user_group.save(update_fields=['name'])
except django.db.utils.IntegrityError: except django.db.utils.IntegrityError:
raise JsonableError(_("User group '%s' already exists.") % (name,)) raise JsonableError(_("User group '{}' already exists.").format(name))
do_send_user_group_update_event(user_group, dict(name=name)) do_send_user_group_update_event(user_group, dict(name=name))
def do_update_user_group_description(user_group: UserGroup, description: str) -> None: def do_update_user_group_description(user_group: UserGroup, description: str) -> None:

View File

@ -18,7 +18,7 @@ def get_user_profiles(emails: Iterable[str], realm: Realm) -> List[UserProfile]:
try: try:
user_profile = get_user_including_cross_realm(email, realm) user_profile = get_user_including_cross_realm(email, realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
raise JsonableError(_("Invalid email '%s'") % (email,)) raise JsonableError(_("Invalid email '{}'").format(email))
user_profiles.append(user_profile) user_profiles.append(user_profile)
return user_profiles return user_profiles

View File

@ -174,7 +174,7 @@ def get_existing_user_errors(
if existing_user_profile.is_active: if existing_user_profile.is_active:
if verbose: if verbose:
msg = _('%s already has an account') % (email,) msg = _('{email} already has an account').format(email=email)
else: else:
msg = _("Already has an account.") msg = _("Already has an account.")
else: else:

View File

@ -52,7 +52,7 @@ def emoji_name_to_emoji_code(realm: Realm, emoji_name: str) -> Tuple[str, str]:
return emoji_name, Reaction.ZULIP_EXTRA_EMOJI return emoji_name, Reaction.ZULIP_EXTRA_EMOJI
if emoji_name in name_to_codepoint: if emoji_name in name_to_codepoint:
return name_to_codepoint[emoji_name], Reaction.UNICODE_EMOJI return name_to_codepoint[emoji_name], Reaction.UNICODE_EMOJI
raise JsonableError(_("Emoji '%s' does not exist") % (emoji_name,)) raise JsonableError(_("Emoji '{}' does not exist").format(emoji_name))
def check_emoji_request(realm: Realm, emoji_name: str, emoji_code: str, def check_emoji_request(realm: Realm, emoji_name: str, emoji_code: str,
emoji_type: str) -> None: emoji_type: str) -> None:

View File

@ -21,7 +21,7 @@ def check_supported_events_narrow_filter(narrow: Iterable[Sequence[str]]) -> Non
for element in narrow: for element in narrow:
operator = element[0] operator = element[0]
if operator not in ["stream", "topic", "sender", "is"]: if operator not in ["stream", "topic", "sender", "is"]:
raise JsonableError(_("Operator %s not supported.") % (operator,)) raise JsonableError(_("Operator {} not supported.").format(operator))
def is_web_public_compatible(narrow: Iterable[Dict[str, str]]) -> bool: def is_web_public_compatible(narrow: Iterable[Dict[str, str]]) -> bool:
for element in narrow: for element in narrow:

View File

@ -238,15 +238,17 @@ def parse_gcm_options(options: Dict[str, Any], data: Dict[str, Any]) -> str:
else: # `'event': 'remove'`, presumably else: # `'event': 'remove'`, presumably
priority = 'normal' priority = 'normal'
if priority not in ('normal', 'high'): if priority not in ('normal', 'high'):
raise JsonableError(_("Invalid GCM option to bouncer: priority %r") raise JsonableError(_(
% (priority,)) "Invalid GCM option to bouncer: priority {!r}",
).format(priority))
if options: if options:
# We're strict about the API; there is no use case for a newer Zulip # We're strict about the API; there is no use case for a newer Zulip
# server talking to an older bouncer, so we only need to provide # server talking to an older bouncer, so we only need to provide
# one-way compatibility. # one-way compatibility.
raise JsonableError(_("Invalid GCM options to bouncer: %s") raise JsonableError(_(
% (ujson.dumps(options),)) "Invalid GCM options to bouncer: {}",
).format(ujson.dumps(options)))
return priority # when this grows a second option, can make it a tuple return priority # when this grows a second option, can make it a tuple
@ -600,9 +602,9 @@ def get_apns_alert_subtitle(message: Message) -> str:
On an iOS notification, this is the second bolded line. On an iOS notification, this is the second bolded line.
""" """
if message.trigger == "mentioned": if message.trigger == "mentioned":
return _("%(full_name)s mentioned you:") % dict(full_name=message.sender.full_name) return _("{full_name} mentioned you:").format(full_name=message.sender.full_name)
elif message.trigger == "wildcard_mentioned": elif message.trigger == "wildcard_mentioned":
return _("%(full_name)s mentioned everyone:") % dict(full_name=message.sender.full_name) return _("{full_name} mentioned everyone:").format(full_name=message.sender.full_name)
elif message.recipient.type == Recipient.PERSONAL: elif message.recipient.type == Recipient.PERSONAL:
return "" return ""
# For group PMs, or regular messages to a stream, just use a colon to indicate this is the sender. # For group PMs, or regular messages to a stream, just use a colon to indicate this is the sender.

View File

@ -77,7 +77,7 @@ def send_to_push_bouncer(method: str,
if 'code' in result_dict and result_dict['code'] == 'INVALID_ZULIP_SERVER': if 'code' in result_dict and result_dict['code'] == 'INVALID_ZULIP_SERVER':
# Invalid Zulip server credentials should email this server's admins # Invalid Zulip server credentials should email this server's admins
raise PushNotificationBouncerException( raise PushNotificationBouncerException(
_("Push notifications bouncer error: %s") % (msg,)) _("Push notifications bouncer error: {}").format(msg))
else: else:
# But most other errors coming from the push bouncer # But most other errors coming from the push bouncer
# server are client errors (e.g. never-registered token) # server are client errors (e.g. never-registered token)

View File

@ -348,7 +348,7 @@ def has_request_variables(view_func: ViewFuncT) -> ViewFuncT:
try: try:
val = ujson.loads(val) val = ujson.loads(val)
except Exception: except Exception:
raise JsonableError(_('Argument "%s" is not valid JSON.') % (post_var_name,)) raise JsonableError(_('Argument "{}" is not valid JSON.').format(post_var_name))
error = param.validator(post_var_name, val) error = param.validator(post_var_name, val)
if error: if error:

View File

@ -115,12 +115,12 @@ def create_streams_if_needed(realm: Realm,
def check_stream_name(stream_name: str) -> None: def check_stream_name(stream_name: str) -> None:
if stream_name.strip() == "": if stream_name.strip() == "":
raise JsonableError(_("Invalid stream name '%s'") % (stream_name,)) raise JsonableError(_("Invalid stream name '{}'").format(stream_name))
if len(stream_name) > Stream.MAX_NAME_LENGTH: if len(stream_name) > Stream.MAX_NAME_LENGTH:
raise JsonableError(_("Stream name too long (limit: %s characters).") % (Stream.MAX_NAME_LENGTH,)) raise JsonableError(_("Stream name too long (limit: {} characters).").format(Stream.MAX_NAME_LENGTH))
for i in stream_name: for i in stream_name:
if ord(i) == 0: if ord(i) == 0:
raise JsonableError(_("Stream name '%s' contains NULL (0x00) characters.") % (stream_name,)) raise JsonableError(_("Stream name '{}' contains NULL (0x00) characters.").format(stream_name))
def subscribed_to_stream(user_profile: UserProfile, stream_id: int) -> bool: def subscribed_to_stream(user_profile: UserProfile, stream_id: int) -> bool:
return Subscription.objects.filter( return Subscription.objects.filter(
@ -177,7 +177,7 @@ def access_stream_for_send_message(sender: UserProfile,
return return
# All other cases are an error. # All other cases are an error.
raise JsonableError(_("Not authorized to send to stream '%s'") % (stream.name,)) raise JsonableError(_("Not authorized to send to stream '{}'").format(stream.name))
def check_for_exactly_one_stream_arg(stream_id: Optional[int], stream: Optional[str]) -> None: def check_for_exactly_one_stream_arg(stream_id: Optional[int], stream: Optional[str]) -> None:
if stream_id is None and stream is None: if stream_id is None and stream is None:
@ -276,14 +276,14 @@ def check_stream_name_available(realm: Realm, name: str) -> None:
check_stream_name(name) check_stream_name(name)
try: try:
get_stream(name, realm) get_stream(name, realm)
raise JsonableError(_("Stream name '%s' is already taken.") % (name,)) raise JsonableError(_("Stream name '{}' is already taken.").format(name))
except Stream.DoesNotExist: except Stream.DoesNotExist:
pass pass
def access_stream_by_name(user_profile: UserProfile, def access_stream_by_name(user_profile: UserProfile,
stream_name: str, stream_name: str,
allow_realm_admin: bool=False) -> Tuple[Stream, Recipient, Optional[Subscription]]: allow_realm_admin: bool=False) -> Tuple[Stream, Recipient, Optional[Subscription]]:
error = _("Invalid stream name '%s'") % (stream_name,) error = _("Invalid stream name '{}'").format(stream_name)
try: try:
stream = get_realm_stream(stream_name, user_profile.realm_id) stream = get_realm_stream(stream_name, user_profile.realm_id)
except Stream.DoesNotExist: except Stream.DoesNotExist:
@ -345,7 +345,7 @@ def can_access_stream_history(user_profile: UserProfile, stream: Stream) -> bool
if stream.is_history_public_to_subscribers(): if stream.is_history_public_to_subscribers():
# In this case, we check if the user is subscribed. # In this case, we check if the user is subscribed.
error = _("Invalid stream name '%s'") % (stream.name,) error = _("Invalid stream name '{}'").format(stream.name)
try: try:
(recipient, sub) = access_stream_common(user_profile, stream, error) (recipient, sub) = access_stream_common(user_profile, stream, error)
except JsonableError: except JsonableError:
@ -440,8 +440,9 @@ def list_to_streams(streams_raw: Iterable[Mapping[str, Any]],
if not user_profile.can_create_streams(): if not user_profile.can_create_streams():
raise JsonableError(_('User cannot create streams.')) raise JsonableError(_('User cannot create streams.'))
elif not autocreate: elif not autocreate:
raise JsonableError(_("Stream(s) (%s) do not exist") % ", ".join( raise JsonableError(_("Stream(s) ({}) do not exist").format(
stream_dict["name"] for stream_dict in missing_stream_dicts)) ", ".join(stream_dict["name"] for stream_dict in missing_stream_dicts),
))
# We already filtered out existing streams, so dup_streams # We already filtered out existing streams, so dup_streams
# will normally be an empty list below, but we protect against somebody # will normally be an empty list below, but we protect against somebody
@ -458,7 +459,7 @@ def access_default_stream_group_by_id(realm: Realm, group_id: int) -> DefaultStr
try: try:
return DefaultStreamGroup.objects.get(realm=realm, id=group_id) return DefaultStreamGroup.objects.get(realm=realm, id=group_id)
except DefaultStreamGroup.DoesNotExist: except DefaultStreamGroup.DoesNotExist:
raise JsonableError(_("Default stream group with id '%s' does not exist.") % (group_id,)) raise JsonableError(_("Default stream group with id '{}' does not exist.").format(group_id))
def get_stream_by_narrow_operand_access_unchecked(operand: Union[str, int], realm: Realm) -> Stream: def get_stream_by_narrow_operand_access_unchecked(operand: Union[str, int], realm: Realm) -> Stream:
"""This is required over access_stream_* in certain cases where """This is required over access_stream_* in certain cases where

View File

@ -78,12 +78,13 @@ def check_valid_bot_config(bot_type: int, service_name: str,
config_options = {c[1]: c[2] for c in integration.config_options} config_options = {c[1]: c[2] for c in integration.config_options}
break break
if not config_options: if not config_options:
raise JsonableError(_("Invalid integration '%s'.") % (service_name,)) raise JsonableError(_("Invalid integration '{}'.").format(service_name))
missing_keys = set(config_options.keys()) - set(config_data.keys()) missing_keys = set(config_options.keys()) - set(config_data.keys())
if missing_keys: if missing_keys:
raise JsonableError(_("Missing configuration parameters: %s") % ( raise JsonableError(_("Missing configuration parameters: {}").format(
missing_keys,)) missing_keys,
))
for key, validator in config_options.items(): for key, validator in config_options.items():
value = config_data[key] value = config_data[key]
@ -196,12 +197,12 @@ def user_ids_to_users(user_ids: Sequence[int], realm: Realm) -> List[UserProfile
found_user_ids = user_profiles_by_id.keys() 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] missed_user_ids = [user_id for user_id in user_ids if user_id not in found_user_ids]
if missed_user_ids: if missed_user_ids:
raise JsonableError(_("Invalid user ID: %s") % (missed_user_ids[0],)) raise JsonableError(_("Invalid user ID: {}").format(missed_user_ids[0]))
user_profiles = list(user_profiles_by_id.values()) user_profiles = list(user_profiles_by_id.values())
for user_profile in user_profiles: for user_profile in user_profiles:
if user_profile.realm != realm: if user_profile.realm != realm:
raise JsonableError(_("Invalid user ID: %s") % (user_profile.id,)) raise JsonableError(_("Invalid user ID: {}").format(user_profile.id))
return user_profiles return user_profiles
def access_bot_by_id(user_profile: UserProfile, user_id: int) -> UserProfile: def access_bot_by_id(user_profile: UserProfile, user_id: int) -> UserProfile:

View File

@ -56,7 +56,7 @@ def set_type_structure(type_structure: TypeStructure) -> Callable[[FuncT], Any]:
@set_type_structure("str") @set_type_structure("str")
def check_string(var_name: str, val: object) -> Optional[str]: def check_string(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, str): if not isinstance(val, str):
return _('%s is not a string') % (var_name,) return _('{var_name} is not a string').format(var_name=var_name)
return None return None
@set_type_structure("str") @set_type_structure("str")
@ -78,7 +78,7 @@ def check_string_in(possible_values: Union[Set[str], List[str]]) -> Validator:
if not_str is not None: if not_str is not None:
return not_str return not_str
if val not in possible_values: if val not in possible_values:
return _("Invalid %s") % (var_name,) return _("Invalid {var_name}").format(var_name=var_name)
return None return None
return validator return validator
@ -91,7 +91,7 @@ def check_capped_string(max_length: int) -> Validator:
@set_type_structure("str") @set_type_structure("str")
def validator(var_name: str, val: object) -> Optional[str]: def validator(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, str): if not isinstance(val, str):
return _('%s is not a string') % (var_name,) return _('{var_name} is not a string').format(var_name=var_name)
if len(val) > max_length: if len(val) > max_length:
return _("{var_name} is too long (limit: {max_length} characters)").format( return _("{var_name} is too long (limit: {max_length} characters)").format(
var_name=var_name, max_length=max_length) var_name=var_name, max_length=max_length)
@ -103,7 +103,7 @@ def check_string_fixed_length(length: int) -> Validator:
@set_type_structure("str") @set_type_structure("str")
def validator(var_name: str, val: object) -> Optional[str]: def validator(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, str): if not isinstance(val, str):
return _('%s is not a string') % (var_name,) return _('{var_name} is not a string').format(var_name=var_name)
if len(val) != length: if len(val) != length:
return _("{var_name} has incorrect length {length}; should be {target_length}").format( return _("{var_name} has incorrect length {length}; should be {target_length}").format(
var_name=var_name, target_length=length, length=len(val)) var_name=var_name, target_length=length, length=len(val))
@ -117,17 +117,17 @@ def check_long_string(var_name: str, val: object) -> Optional[str]:
@set_type_structure("date") @set_type_structure("date")
def check_date(var_name: str, val: object) -> Optional[str]: def check_date(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, str): if not isinstance(val, str):
return _('%s is not a string') % (var_name,) return _('{var_name} is not a string').format(var_name=var_name)
try: try:
datetime.strptime(val, '%Y-%m-%d') datetime.strptime(val, '%Y-%m-%d')
except ValueError: except ValueError:
return _('%s is not a date') % (var_name,) return _('{var_name} is not a date').format(var_name=var_name)
return None return None
@set_type_structure("int") @set_type_structure("int")
def check_int(var_name: str, val: object) -> Optional[str]: def check_int(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, int): if not isinstance(val, int):
return _('%s is not an integer') % (var_name,) return _('{var_name} is not an integer').format(var_name=var_name)
return None return None
def check_int_in(possible_values: List[int]) -> Validator: def check_int_in(possible_values: List[int]) -> Validator:
@ -137,7 +137,7 @@ def check_int_in(possible_values: List[int]) -> Validator:
if not_int is not None: if not_int is not None:
return not_int return not_int
if val not in possible_values: if val not in possible_values:
return _("Invalid %s") % (var_name,) return _("Invalid {var_name}").format(var_name=var_name)
return None return None
return validator return validator
@ -145,23 +145,23 @@ def check_int_in(possible_values: List[int]) -> Validator:
@set_type_structure("float") @set_type_structure("float")
def check_float(var_name: str, val: object) -> Optional[str]: def check_float(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, float): if not isinstance(val, float):
return _('%s is not a float') % (var_name,) return _('{var_name} is not a float').format(var_name=var_name)
return None return None
@set_type_structure("bool") @set_type_structure("bool")
def check_bool(var_name: str, val: object) -> Optional[str]: def check_bool(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, bool): if not isinstance(val, bool):
return _('%s is not a boolean') % (var_name,) return _('{var_name} is not a boolean').format(var_name=var_name)
return None return None
@set_type_structure("str") @set_type_structure("str")
def check_color(var_name: str, val: object) -> Optional[str]: def check_color(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, str): if not isinstance(val, str):
return _('%s is not a string') % (var_name,) return _('{var_name} is not a string').format(var_name=var_name)
valid_color_pattern = re.compile(r'^#([a-fA-F0-9]{3,6})$') valid_color_pattern = re.compile(r'^#([a-fA-F0-9]{3,6})$')
matched_results = valid_color_pattern.match(val) matched_results = valid_color_pattern.match(val)
if not matched_results: if not matched_results:
return _('%s is not a valid hex color code') % (var_name,) return _('{var_name} is not a valid hex color code').format(var_name=var_name)
return None return None
def check_none_or(sub_validator: Validator) -> Validator: def check_none_or(sub_validator: Validator) -> Validator:
@ -190,11 +190,12 @@ def check_list(sub_validator: Optional[Validator], length: Optional[int]=None) -
@set_type_structure(type_structure) @set_type_structure(type_structure)
def f(var_name: str, val: object) -> Optional[str]: def f(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, list): if not isinstance(val, list):
return _('%s is not a list') % (var_name,) return _('{var_name} is not a list').format(var_name=var_name)
if length is not None and length != len(val): if length is not None and length != len(val):
return (_('%(container)s should have exactly %(length)s items') % return (_('{container} should have exactly {length} items').format(
{'container': var_name, 'length': length}) container=var_name, length=length,
))
if sub_validator: if sub_validator:
for i, item in enumerate(val): for i, item in enumerate(val):
@ -215,12 +216,13 @@ def check_dict(required_keys: Iterable[Tuple[str, Validator]]=[],
@set_type_structure(type_structure) @set_type_structure(type_structure)
def f(var_name: str, val: object) -> Optional[str]: def f(var_name: str, val: object) -> Optional[str]:
if not isinstance(val, dict): if not isinstance(val, dict):
return _('%s is not a dict') % (var_name,) return _('{var_name} is not a dict').format(var_name=var_name)
for k, sub_validator in required_keys: for k, sub_validator in required_keys:
if k not in val: if k not in val:
return (_('%(key_name)s key is missing from %(var_name)s') % return (_('{key_name} key is missing from {var_name}').format(
{'key_name': k, 'var_name': var_name}) key_name=k, var_name=var_name,
))
vname = f'{var_name}["{k}"]' vname = f'{var_name}["{k}"]'
error = sub_validator(vname, val[k]) error = sub_validator(vname, val[k])
if error: if error:
@ -251,7 +253,7 @@ def check_dict(required_keys: Iterable[Tuple[str, Validator]]=[],
optional_keys_set = {x[0] for x in optional_keys} optional_keys_set = {x[0] for x in optional_keys}
delta_keys = set(val.keys()) - required_keys_set - optional_keys_set delta_keys = set(val.keys()) - required_keys_set - optional_keys_set
if len(delta_keys) != 0: if len(delta_keys) != 0:
return _("Unexpected arguments: %s") % (", ".join(list(delta_keys)),) return _("Unexpected arguments: {}").format(", ".join(list(delta_keys)))
return None return None
@ -280,17 +282,16 @@ def check_variable_type(allowed_type_funcs: Iterable[Validator]) -> Validator:
for func in allowed_type_funcs: for func in allowed_type_funcs:
if not func(var_name, val): if not func(var_name, val):
return None return None
return _('%s is not an allowed_type') % (var_name,) return _('{var_name} is not an allowed_type').format(var_name=var_name)
return enumerated_type_check return enumerated_type_check
def equals(expected_val: object) -> Validator: def equals(expected_val: object) -> Validator:
@set_type_structure(f'equals("{str(expected_val)}")') @set_type_structure(f'equals("{str(expected_val)}")')
def f(var_name: str, val: object) -> Optional[str]: def f(var_name: str, val: object) -> Optional[str]:
if val != expected_val: if val != expected_val:
return (_('%(variable)s != %(expected_value)s (%(value)s is wrong)') % return (_('{variable} != {expected_value} ({value} is wrong)').format(
{'variable': var_name, variable=var_name, expected_value=expected_val, value=val,
'expected_value': expected_val, ))
'value': val})
return None return None
return f return f
@ -313,7 +314,7 @@ def check_url(var_name: str, val: object) -> Optional[str]:
validate(val) validate(val)
return None return None
except ValidationError: except ValidationError:
return _('%s is not a URL') % (var_name,) return _('{var_name} is not a URL').format(var_name=var_name)
@set_type_structure('str') @set_type_structure('str')
def check_external_account_url_pattern(var_name: str, val: object) -> Optional[str]: def check_external_account_url_pattern(var_name: str, val: object) -> Optional[str]:
@ -435,7 +436,7 @@ def check_string_or_int_list(var_name: str, val: object) -> Optional[str]:
return None return None
if not isinstance(val, list): if not isinstance(val, list):
return _('%s is not a string or an integer list') % (var_name,) return _('{var_name} is not a string or an integer list').format(var_name=var_name)
return check_list(check_int)(var_name, val) return check_list(check_int)(var_name, val)
@ -444,4 +445,4 @@ def check_string_or_int(var_name: str, val: object) -> Optional[str]:
if isinstance(val, str) or isinstance(val, int): if isinstance(val, str) or isinstance(val, int):
return None return None
return _('%s is not a string or integer') % (var_name,) return _('{var_name} is not a string or integer').format(var_name=var_name)

View File

@ -54,4 +54,4 @@ def process_zcommands(content: str, user_profile: UserProfile) -> Dict[str, Any]
switch_command='fluid-width', switch_command='fluid-width',
setting='fluid_layout_width', setting='fluid_layout_width',
setting_value=False)) setting_value=False))
raise JsonableError(_('No such command: %s') % (command,)) raise JsonableError(_('No such command: {}').format(command))

View File

@ -211,7 +211,7 @@ class RealmEmojiTest(ZulipTestCase):
with get_test_image_file('img.png') as fp: with get_test_image_file('img.png') as fp:
with self.settings(MAX_EMOJI_FILE_SIZE=0): with self.settings(MAX_EMOJI_FILE_SIZE=0):
result = self.client_post('/json/realm/emoji/my_emoji', {'file': fp}) result = self.client_post('/json/realm/emoji/my_emoji', {'file': fp})
self.assert_json_error(result, 'Uploaded file is larger than the allowed limit of 0 MB') self.assert_json_error(result, 'Uploaded file is larger than the allowed limit of 0 MiB')
def test_upload_already_existed_emoji(self) -> None: def test_upload_already_existed_emoji(self) -> None:
self.login('iago') self.login('iago')

View File

@ -164,7 +164,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
# would be 1MB. # would be 1MB.
with self.settings(MAX_FILE_UPLOAD_SIZE=0): with self.settings(MAX_FILE_UPLOAD_SIZE=0):
result = self.client_post("/json/user_uploads", {'f1': fp}) result = self.client_post("/json/user_uploads", {'f1': fp})
self.assert_json_error(result, 'Uploaded file is larger than the allowed limit of 0 MB') self.assert_json_error(result, 'Uploaded file is larger than the allowed limit of 0 MiB')
def test_multiple_upload_failure(self) -> None: def test_multiple_upload_failure(self) -> None:
""" """
@ -1163,7 +1163,7 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase):
with get_test_image_file(self.correct_files[0][0]) as fp: with get_test_image_file(self.correct_files[0][0]) as fp:
with self.settings(MAX_AVATAR_FILE_SIZE=0): with self.settings(MAX_AVATAR_FILE_SIZE=0):
result = self.client_post("/json/users/me/avatar", {'file': fp}) result = self.client_post("/json/users/me/avatar", {'file': fp})
self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MB") self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MiB")
def tearDown(self) -> None: def tearDown(self) -> None:
destroy_uploads() destroy_uploads()
@ -1336,7 +1336,7 @@ class RealmIconTest(UploadSerializeMixin, ZulipTestCase):
with get_test_image_file(self.correct_files[0][0]) as fp: with get_test_image_file(self.correct_files[0][0]) as fp:
with self.settings(MAX_ICON_FILE_SIZE=0): with self.settings(MAX_ICON_FILE_SIZE=0):
result = self.client_post("/json/realm/icon", {'file': fp}) result = self.client_post("/json/realm/icon", {'file': fp})
self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MB") self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MiB")
def tearDown(self) -> None: def tearDown(self) -> None:
destroy_uploads() destroy_uploads()
@ -1479,7 +1479,7 @@ class RealmLogoTest(UploadSerializeMixin, ZulipTestCase):
with self.settings(MAX_LOGO_FILE_SIZE=0): with self.settings(MAX_LOGO_FILE_SIZE=0):
result = self.client_post("/json/realm/logo", {'file': fp, 'night': result = self.client_post("/json/realm/logo", {'file': fp, 'night':
ujson.dumps(self.night)}) ujson.dumps(self.night)})
self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MB") self.assert_json_error(result, "Uploaded file is larger than the allowed limit of 0 MiB")
def tearDown(self) -> None: def tearDown(self) -> None:
destroy_uploads() destroy_uploads()

View File

@ -566,13 +566,17 @@ def fetch_events(query: Mapping[str, Any]) -> Dict[str, Any]:
client.event_queue.newest_pruned_id is not None client.event_queue.newest_pruned_id is not None
and last_event_id < client.event_queue.newest_pruned_id and last_event_id < client.event_queue.newest_pruned_id
): ):
raise JsonableError(_("An event newer than %s has already been pruned!") % (last_event_id,)) raise JsonableError(_("An event newer than {event_id} has already been pruned!").format(
event_id=last_event_id,
))
client.event_queue.prune(last_event_id) client.event_queue.prune(last_event_id)
if ( if (
client.event_queue.newest_pruned_id is not None client.event_queue.newest_pruned_id is not None
and last_event_id != client.event_queue.newest_pruned_id and last_event_id != client.event_queue.newest_pruned_id
): ):
raise JsonableError(_("Event %s was not in this queue") % (last_event_id,)) raise JsonableError(_("Event {event_id} was not in this queue").format(
event_id=last_event_id,
))
was_connected = client.finish_current_handler() was_connected = client.finish_current_handler()
if not client.event_queue.empty() or dont_block: if not client.event_queue.empty() or dont_block:

View File

@ -15,6 +15,6 @@ from zerver.models import UserProfile
def mark_hotspot_as_read(request: HttpRequest, user: UserProfile, def mark_hotspot_as_read(request: HttpRequest, user: UserProfile,
hotspot: str=REQ(validator=check_string)) -> HttpResponse: hotspot: str=REQ(validator=check_string)) -> HttpResponse:
if hotspot not in ALL_HOTSPOTS: if hotspot not in ALL_HOTSPOTS:
return json_error(_('Unknown hotspot: %s') % (hotspot,)) return json_error(_('Unknown hotspot: {}').format(hotspot))
do_mark_hotspot_as_read(user, hotspot) do_mark_hotspot_as_read(user, hotspot)
return json_success() return json_success()

View File

@ -852,8 +852,9 @@ def get_messages_backend(request: HttpRequest, user_profile: UserProfile,
apply_markdown: bool=REQ(validator=check_bool, default=True)) -> HttpResponse: apply_markdown: bool=REQ(validator=check_bool, default=True)) -> HttpResponse:
anchor = parse_anchor_value(anchor_val, use_first_unread_anchor_val) anchor = parse_anchor_value(anchor_val, use_first_unread_anchor_val)
if num_before + num_after > MAX_MESSAGES_PER_FETCH: if num_before + num_after > MAX_MESSAGES_PER_FETCH:
return json_error(_("Too many messages requested (maximum %s).") return json_error(_("Too many messages requested (maximum {}).").format(
% (MAX_MESSAGES_PER_FETCH,)) MAX_MESSAGES_PER_FETCH,
))
if user_profile.realm.email_address_visibility != Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE: if user_profile.realm.email_address_visibility != Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE:
# If email addresses are only available to administrators, # If email addresses are only available to administrators,
@ -1218,7 +1219,7 @@ def mark_topic_as_read(request: HttpRequest,
) )
if not topic_exists: if not topic_exists:
raise JsonableError(_('No such topic \'%s\'') % (topic_name,)) raise JsonableError(_('No such topic \'{}\'').format(topic_name))
count = do_mark_stream_messages_as_read(user_profile, request.client, stream, topic_name) count = do_mark_stream_messages_as_read(user_profile, request.client, stream, topic_name)
@ -1413,7 +1414,7 @@ def send_message_backend(request: HttpRequest, user_profile: UserProfile,
try: try:
realm = get_realm(realm_str) realm = get_realm(realm_str)
except Realm.DoesNotExist: except Realm.DoesNotExist:
return json_error(_("Unknown organization '%s'") % (realm_str,)) return json_error(_("Unknown organization '{}'").format(realm_str))
if client.name in ["zephyr_mirror", "irc_mirror", "jabber_mirror", "JabberMirror"]: if client.name in ["zephyr_mirror", "irc_mirror", "jabber_mirror", "JabberMirror"]:
# Here's how security works for mirroring: # Here's how security works for mirroring:

View File

@ -30,7 +30,7 @@ def get_presence_backend(request: HttpRequest, user_profile: UserProfile,
presence_dict = get_presence_for_user(target.id) presence_dict = get_presence_for_user(target.id)
if len(presence_dict) == 0: if len(presence_dict) == 0:
return json_error(_('No presence data for %s') % (email,)) return json_error(_('No presence data for {email}').format(email=email))
# For initial version, we just include the status and timestamp keys # For initial version, we just include the status and timestamp keys
result = dict(presence=presence_dict[target.email]) result = dict(presence=presence_dict[target.email])
@ -77,7 +77,7 @@ def update_active_status_backend(request: HttpRequest, user_profile: UserProfile
) -> HttpResponse: ) -> HttpResponse:
status_val = UserPresence.status_from_string(status) status_val = UserPresence.status_from_string(status)
if status_val is None: if status_val is None:
raise JsonableError(_("Invalid status: %s") % (status,)) raise JsonableError(_("Invalid status: {}").format(status))
elif user_profile.presence_enabled: elif user_profile.presence_enabled:
update_user_presence(user_profile, request.client, timezone_now(), update_user_presence(user_profile, request.client, timezone_now(),
status_val, new_user_input) status_val, new_user_input)

View File

@ -94,7 +94,7 @@ def update_realm(
# Additional validation/error checking beyond types go here, so # Additional validation/error checking beyond types go here, so
# the entire request can succeed or fail atomically. # the entire request can succeed or fail atomically.
if default_language is not None and default_language not in get_available_language_codes(): if default_language is not None and default_language not in get_available_language_codes():
raise JsonableError(_("Invalid language '%s'") % (default_language,)) raise JsonableError(_("Invalid language '{}'").format(default_language))
if description is not None and len(description) > 1000: if description is not None and len(description) > 1000:
return json_error(_("Organization description is too long.")) return json_error(_("Organization description is too long."))
if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH: if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH:

View File

@ -26,8 +26,8 @@ def create_realm_domain(request: HttpRequest, user_profile: UserProfile,
except ValidationError as e: except ValidationError as e:
return json_error(_('Invalid domain: {}').format(e.messages[0])) return json_error(_('Invalid domain: {}').format(e.messages[0]))
if RealmDomain.objects.filter(realm=user_profile.realm, domain=domain).exists(): if RealmDomain.objects.filter(realm=user_profile.realm, domain=domain).exists():
return json_error(_("The domain %(domain)s is already" return json_error(_("The domain {domain} is already"
" a part of your organization.") % {'domain': domain}) " a part of your organization.").format(domain=domain))
realm_domain = do_add_realm_domain(user_profile.realm, domain, allow_subdomains) realm_domain = do_add_realm_domain(user_profile.realm, domain, allow_subdomains)
return json_success({'new_domain': [realm_domain.id, realm_domain.domain]}) return json_success({'new_domain': [realm_domain.id, realm_domain.domain]})
@ -39,7 +39,7 @@ def patch_realm_domain(request: HttpRequest, user_profile: UserProfile, domain:
realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain) realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain)
do_change_realm_domain(realm_domain, allow_subdomains) do_change_realm_domain(realm_domain, allow_subdomains)
except RealmDomain.DoesNotExist: except RealmDomain.DoesNotExist:
return json_error(_('No entry found for domain %(domain)s.') % {'domain': domain}) return json_error(_('No entry found for domain {domain}.').format(domain=domain))
return json_success() return json_success()
@require_realm_admin @require_realm_admin
@ -50,5 +50,5 @@ def delete_realm_domain(request: HttpRequest, user_profile: UserProfile,
realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain) realm_domain = RealmDomain.objects.get(realm=user_profile.realm, domain=domain)
do_remove_realm_domain(realm_domain) do_remove_realm_domain(realm_domain)
except RealmDomain.DoesNotExist: except RealmDomain.DoesNotExist:
return json_error(_('No entry found for domain %(domain)s.') % {'domain': domain}) return json_error(_('No entry found for domain {domain}.').format(domain=domain))
return json_success() return json_success()

View File

@ -32,8 +32,9 @@ def upload_emoji(request: HttpRequest, user_profile: UserProfile,
return json_error(_("You must upload exactly one file.")) return json_error(_("You must upload exactly one file."))
emoji_file = list(request.FILES.values())[0] emoji_file = list(request.FILES.values())[0]
if (settings.MAX_EMOJI_FILE_SIZE * 1024 * 1024) < emoji_file.size: if (settings.MAX_EMOJI_FILE_SIZE * 1024 * 1024) < emoji_file.size:
return json_error(_("Uploaded file is larger than the allowed limit of %s MB") % ( return json_error(_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_EMOJI_FILE_SIZE)) settings.MAX_EMOJI_FILE_SIZE,
))
realm_emoji = check_add_realm_emoji(user_profile.realm, realm_emoji = check_add_realm_emoji(user_profile.realm,
emoji_name, emoji_name,
@ -49,7 +50,7 @@ def delete_emoji(request: HttpRequest, user_profile: UserProfile,
if not RealmEmoji.objects.filter(realm=user_profile.realm, if not RealmEmoji.objects.filter(realm=user_profile.realm,
name=emoji_name, name=emoji_name,
deactivated=False).exists(): deactivated=False).exists():
raise JsonableError(_("Emoji '%s' does not exist") % (emoji_name,)) raise JsonableError(_("Emoji '{}' does not exist").format(emoji_name))
check_emoji_admin(user_profile, emoji_name) check_emoji_admin(user_profile, emoji_name)
do_remove_realm_emoji(user_profile.realm, emoji_name) do_remove_realm_emoji(user_profile.realm, emoji_name)
return json_success() return json_success()

View File

@ -43,8 +43,9 @@ def export_realm(request: HttpRequest, user: UserProfile) -> HttpResponse:
property='messages_sent:client:day')) property='messages_sent:client:day'))
if (total_messages > MAX_MESSAGE_HISTORY or if (total_messages > MAX_MESSAGE_HISTORY or
user.realm.currently_used_upload_space_bytes() > MAX_UPLOAD_QUOTA): user.realm.currently_used_upload_space_bytes() > MAX_UPLOAD_QUOTA):
return json_error(_('Please request a manual export from %s.') % ( return json_error(_('Please request a manual export from {email}.').format(
settings.ZULIP_ADMINISTRATOR,)) email=settings.ZULIP_ADMINISTRATOR,
))
row = RealmAuditLog.objects.create(realm=realm, row = RealmAuditLog.objects.create(realm=realm,
event_type=event_type, event_type=event_type,

View File

@ -20,8 +20,9 @@ def upload_icon(request: HttpRequest, user_profile: UserProfile) -> HttpResponse
icon_file = list(request.FILES.values())[0] icon_file = list(request.FILES.values())[0]
if ((settings.MAX_ICON_FILE_SIZE * 1024 * 1024) < icon_file.size): if ((settings.MAX_ICON_FILE_SIZE * 1024 * 1024) < icon_file.size):
return json_error(_("Uploaded file is larger than the allowed limit of %s MB") % ( return json_error(_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_ICON_FILE_SIZE)) settings.MAX_ICON_FILE_SIZE,
))
upload_icon_image(icon_file, user_profile) upload_icon_image(icon_file, user_profile)
do_change_icon_source(user_profile.realm, user_profile.realm.ICON_UPLOADED) do_change_icon_source(user_profile.realm, user_profile.realm.ICON_UPLOADED)
icon_url = realm_icon_url(user_profile.realm) icon_url = realm_icon_url(user_profile.realm)

View File

@ -24,8 +24,9 @@ def upload_logo(request: HttpRequest, user_profile: UserProfile,
return json_error(_("You must upload exactly one logo.")) return json_error(_("You must upload exactly one logo."))
logo_file = list(request.FILES.values())[0] logo_file = list(request.FILES.values())[0]
if ((settings.MAX_LOGO_FILE_SIZE * 1024 * 1024) < logo_file.size): if ((settings.MAX_LOGO_FILE_SIZE * 1024 * 1024) < logo_file.size):
return json_error(_("Uploaded file is larger than the allowed limit of %s MB") % ( return json_error(_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_LOGO_FILE_SIZE)) settings.MAX_LOGO_FILE_SIZE,
))
upload_logo_image(logo_file, user_profile, night) upload_logo_image(logo_file, user_profile, night)
do_change_logo_source(user_profile.realm, user_profile.realm.LOGO_UPLOADED, night) do_change_logo_source(user_profile.realm, user_profile.realm.LOGO_UPLOADED, night)
return json_success() return json_success()

View File

@ -356,12 +356,14 @@ def you_were_just_subscribed_message(acting_user: UserProfile,
stream_names: Set[str]) -> str: stream_names: Set[str]) -> str:
subscriptions = sorted(list(stream_names)) subscriptions = sorted(list(stream_names))
if len(subscriptions) == 1: if len(subscriptions) == 1:
return _("@**%(full_name)s** subscribed you to the stream #**%(stream_name)s**.") % \ return _("@**{full_name}** subscribed you to the stream #**{stream_name}**.").format(
{"full_name": acting_user.full_name, full_name=acting_user.full_name,
"stream_name": subscriptions[0]} stream_name=subscriptions[0],
)
message = _("@**%(full_name)s** subscribed you to the following streams:") % \ message = _("@**{full_name}** subscribed you to the following streams:").format(
{"full_name": acting_user.full_name} full_name=acting_user.full_name,
)
message += "\n\n" message += "\n\n"
for stream_name in subscriptions: for stream_name in subscriptions:
message += f"* #**{stream_name}**\n" message += f"* #**{stream_name}**\n"
@ -416,7 +418,9 @@ def add_subscriptions_backend(
authorized_streams, unauthorized_streams = \ authorized_streams, unauthorized_streams = \
filter_stream_authorization(user_profile, existing_streams) filter_stream_authorization(user_profile, existing_streams)
if len(unauthorized_streams) > 0 and authorization_errors_fatal: if len(unauthorized_streams) > 0 and authorization_errors_fatal:
return json_error(_("Unable to access stream (%s).") % unauthorized_streams[0].name) return json_error(_("Unable to access stream ({stream_name}).").format(
stream_name=unauthorized_streams[0].name,
))
# Newly created streams are also authorized for the creator # Newly created streams are also authorized for the creator
streams = authorized_streams + created_streams streams = authorized_streams + created_streams
@ -519,9 +523,10 @@ def add_subscriptions_backend(
sender=sender, sender=sender,
stream=stream, stream=stream,
topic=Realm.STREAM_EVENTS_NOTIFICATION_TOPIC, topic=Realm.STREAM_EVENTS_NOTIFICATION_TOPIC,
content=_('Stream created by @_**%(user_name)s|%(user_id)d**.') % { content=_('Stream created by @_**{user_name}|{user_id}**.').format(
'user_name': user_profile.full_name, user_name=user_profile.full_name,
'user_id': user_profile.id}, user_id=user_profile.id,
),
), ),
) )
@ -675,11 +680,11 @@ def update_subscription_properties_backend(
value = change["value"] value = change["value"]
if property not in property_converters: if property not in property_converters:
return json_error(_("Unknown subscription property: %s") % (property,)) return json_error(_("Unknown subscription property: {}").format(property))
(stream, recipient, sub) = access_stream_by_id(user_profile, stream_id) (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)
if sub is None: if sub is None:
return json_error(_("Not subscribed to stream id %d") % (stream_id,)) return json_error(_("Not subscribed to stream id {}").format(stream_id))
property_conversion = property_converters[property](property, value) property_conversion = property_converters[property](property, value)
if property_conversion: if property_conversion:

View File

@ -107,8 +107,9 @@ def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> Http
user_file = list(request.FILES.values())[0] user_file = list(request.FILES.values())[0]
file_size = user_file.size file_size = user_file.size
if settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024 < file_size: if settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024 < file_size:
return json_error(_("Uploaded file is larger than the allowed limit of %s MB") % ( return json_error(_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_FILE_UPLOAD_SIZE)) settings.MAX_FILE_UPLOAD_SIZE,
))
check_upload_within_quota(user_profile.realm, file_size) check_upload_within_quota(user_profile.realm, file_size)
uri = upload_message_image_from_request(request, user_file, user_profile) uri = upload_message_image_from_request(request, user_file, user_profile)

View File

@ -99,7 +99,9 @@ def add_members_to_group_backend(request: HttpRequest, user_profile: UserProfile
for user_profile in user_profiles: for user_profile in user_profiles:
if user_profile.id in existing_member_ids: if user_profile.id in existing_member_ids:
raise JsonableError(_("User %s is already a member of this group") % (user_profile.id,)) raise JsonableError(_("User {user_id} is already a member of this group").format(
user_id=user_profile.id,
))
bulk_add_members_to_user_group(user_group, user_profiles) bulk_add_members_to_user_group(user_group, user_profiles)
return json_success() return json_success()
@ -114,7 +116,7 @@ def remove_members_from_group_backend(request: HttpRequest, user_profile: UserPr
group_member_ids = get_user_group_members(user_group) group_member_ids = get_user_group_members(user_group)
for member in members: for member in members:
if (member not in group_member_ids): if (member not in group_member_ids):
raise JsonableError(_("There is no member '%s' in this user group") % (member,)) raise JsonableError(_("There is no member '{}' in this user group").format(member))
remove_members_from_user_group(user_group, user_profiles) remove_members_from_user_group(user_group, user_profiles)
return json_success() return json_success()

View File

@ -95,7 +95,7 @@ def json_change_settings(request: HttpRequest, user_profile: UserProfile,
except RateLimited as e: except RateLimited as e:
secs_to_freedom = int(float(str(e))) secs_to_freedom = int(float(str(e)))
return json_error( return json_error(
_("You're making too many attempts! Try again in %s seconds.") % (secs_to_freedom,), _("You're making too many attempts! Try again in {} seconds.").format(secs_to_freedom),
) )
if not check_password_strength(new_password): if not check_password_strength(new_password):
@ -221,7 +221,7 @@ def json_change_notify_settings(
if (notification_sound is not None and if (notification_sound is not None and
notification_sound not in get_available_notification_sounds()): notification_sound not in get_available_notification_sounds()):
raise JsonableError(_("Invalid notification sound '%s'") % (notification_sound,)) raise JsonableError(_("Invalid notification sound '{}'").format(notification_sound))
req_vars = {k: v for k, v in list(locals().items()) if k in user_profile.notification_setting_types} req_vars = {k: v for k, v in list(locals().items()) if k in user_profile.notification_setting_types}
@ -241,8 +241,9 @@ def set_avatar_backend(request: HttpRequest, user_profile: UserProfile) -> HttpR
user_file = list(request.FILES.values())[0] user_file = list(request.FILES.values())[0]
if ((settings.MAX_AVATAR_FILE_SIZE * 1024 * 1024) < user_file.size): if ((settings.MAX_AVATAR_FILE_SIZE * 1024 * 1024) < user_file.size):
return json_error(_("Uploaded file is larger than the allowed limit of %s MB") % ( return json_error(_("Uploaded file is larger than the allowed limit of {} MiB").format(
settings.MAX_AVATAR_FILE_SIZE)) settings.MAX_AVATAR_FILE_SIZE,
))
upload_avatar_image(user_file, user_profile, user_profile) upload_avatar_image(user_file, user_profile, user_profile)
do_change_avatar_fields(user_profile, UserProfile.AVATAR_FROM_USER) do_change_avatar_fields(user_profile, UserProfile.AVATAR_FROM_USER)
user_avatar_url = avatar_url(user_profile) user_avatar_url = avatar_url(user_profile)

View File

@ -479,8 +479,9 @@ def create_user_backend(request: HttpRequest, user_profile: UserProfile,
try: try:
email_allowed_for_realm(email, user_profile.realm) email_allowed_for_realm(email, user_profile.realm)
except DomainNotAllowedForRealmError: except DomainNotAllowedForRealmError:
return json_error(_("Email '%(email)s' not allowed in this organization") % return json_error(_("Email '{email}' not allowed in this organization").format(
{'email': email}) email=email,
))
except DisposableEmailError: except DisposableEmailError:
return json_error(_("Disposable email addresses are not allowed in this organization")) return json_error(_("Disposable email addresses are not allowed in this organization"))
except EmailContainsPlusError: except EmailContainsPlusError:
@ -488,7 +489,7 @@ def create_user_backend(request: HttpRequest, user_profile: UserProfile,
try: try:
get_user_by_delivery_email(email, user_profile.realm) get_user_by_delivery_email(email, user_profile.realm)
return json_error(_("Email '%s' already in use") % (email,)) return json_error(_("Email '{}' already in use").format(email))
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
pass pass

View File

@ -146,7 +146,7 @@ def api_freshdesk_webhook(request: HttpRequest, user_profile: UserProfile,
if ticket_data.get(key) is None: if ticket_data.get(key) is None:
logging.warning("Freshdesk webhook error. Payload was:") logging.warning("Freshdesk webhook error. Payload was:")
logging.warning(request.body) logging.warning(request.body)
return json_error(_("Missing key %s in JSON") % (key,)) return json_error(_("Missing key {} in JSON").format(key))
ticket = TicketDict(ticket_data) ticket = TicketDict(ticket_data)

View File

@ -42,7 +42,7 @@ def api_wordpress_webhook(request: HttpRequest, user_profile: UserProfile,
data = WP_LOGIN_TEMPLATE.format(name=user_login) data = WP_LOGIN_TEMPLATE.format(name=user_login)
else: else:
return json_error(_("Unknown WordPress webhook action: %s") % (hook,)) return json_error(_("Unknown WordPress webhook action: {}").format(hook))
topic = 'WordPress Notification' topic = 'WordPress Notification'

View File

@ -74,7 +74,7 @@ def register_remote_server(
url_validator = URLValidator() url_validator = URLValidator()
url_validator('http://' + hostname) url_validator('http://' + hostname)
except ValidationError: except ValidationError:
raise JsonableError(_('%s is not a valid hostname') % (hostname,)) raise JsonableError(_('{} is not a valid hostname').format(hostname))
try: try:
validate_email(contact_email) validate_email(contact_email)
@ -179,7 +179,7 @@ def validate_incoming_table_data(server: RemoteZulipServer, model: Any,
last_id = get_last_id_from_server(server, model) last_id = get_last_id_from_server(server, model)
for row in rows: for row in rows:
if is_count_stat and row['property'] not in COUNT_STATS: if is_count_stat and row['property'] not in COUNT_STATS:
raise JsonableError(_("Invalid property %s") % (row['property'],)) raise JsonableError(_("Invalid property {}").format(row['property']))
if row['id'] <= last_id: if row['id'] <= last_id:
raise JsonableError(_("Data is out of order.")) raise JsonableError(_("Data is out of order."))
last_id = row['id'] last_id = row['id']