python: Convert percent formatting to Python 3.6 f-strings.

Generated by pyupgrade --py36-plus.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-06-09 21:41:04 -07:00 committed by Tim Abbott
parent 6480deaf27
commit 67e7a3631d
217 changed files with 776 additions and 846 deletions

View File

@ -40,7 +40,7 @@ class CountStat:
self.data_collector = data_collector self.data_collector = data_collector
# might have to do something different for bitfields # might have to do something different for bitfields
if frequency not in self.FREQUENCIES: if frequency not in self.FREQUENCIES:
raise AssertionError("Unknown frequency: %s" % (frequency,)) raise AssertionError(f"Unknown frequency: {frequency}")
self.frequency = frequency self.frequency = frequency
if interval is not None: if interval is not None:
self.interval = interval self.interval = interval
@ -50,7 +50,7 @@ class CountStat:
self.interval = timedelta(days=1) self.interval = timedelta(days=1)
def __str__(self) -> str: def __str__(self) -> str:
return "<CountStat: %s>" % (self.property,) return f"<CountStat: {self.property}>"
class LoggingCountStat(CountStat): class LoggingCountStat(CountStat):
def __init__(self, property: str, output_table: Type[BaseCount], frequency: str) -> None: def __init__(self, property: str, output_table: Type[BaseCount], frequency: str) -> None:
@ -86,11 +86,11 @@ def process_count_stat(stat: CountStat, fill_to_time: datetime,
elif stat.frequency == CountStat.DAY: elif stat.frequency == CountStat.DAY:
time_increment = timedelta(days=1) time_increment = timedelta(days=1)
else: else:
raise AssertionError("Unknown frequency: %s" % (stat.frequency,)) raise AssertionError(f"Unknown frequency: {stat.frequency}")
verify_UTC(fill_to_time) verify_UTC(fill_to_time)
if floor_to_hour(fill_to_time) != fill_to_time: if floor_to_hour(fill_to_time) != fill_to_time:
raise ValueError("fill_to_time must be on an hour boundary: %s" % (fill_to_time,)) raise ValueError(f"fill_to_time must be on an hour boundary: {fill_to_time}")
fill_state = FillState.objects.filter(property=stat.property).first() fill_state = FillState.objects.filter(property=stat.property).first()
if fill_state is None: if fill_state is None:
@ -108,7 +108,7 @@ def process_count_stat(stat: CountStat, fill_to_time: datetime,
elif fill_state.state == FillState.DONE: elif fill_state.state == FillState.DONE:
currently_filled = fill_state.end_time currently_filled = fill_state.end_time
else: else:
raise AssertionError("Unknown value for FillState.state: %s." % (fill_state.state,)) raise AssertionError(f"Unknown value for FillState.state: {fill_state.state}.")
if isinstance(stat, DependentCountStat): if isinstance(stat, DependentCountStat):
for dependency in stat.dependencies: for dependency in stat.dependencies:

View File

@ -43,7 +43,7 @@ def generate_time_series_data(days: int=100, business_hours_base: float=10,
[24*non_business_hours_base] * 2 [24*non_business_hours_base] * 2
holidays = [random() < holiday_rate for i in range(days)] holidays = [random() < holiday_rate for i in range(days)]
else: else:
raise AssertionError("Unknown frequency: %s" % (frequency,)) raise AssertionError(f"Unknown frequency: {frequency}")
if length < 2: if length < 2:
raise AssertionError("Must be generating at least 2 data points. " raise AssertionError("Must be generating at least 2 data points. "
"Currently generating %s" % (length,)) "Currently generating %s" % (length,))

View File

@ -19,7 +19,7 @@ def time_range(start: datetime, end: datetime, frequency: str,
end = floor_to_day(end) end = floor_to_day(end)
step = timedelta(days=1) step = timedelta(days=1)
else: else:
raise AssertionError("Unknown frequency: %s" % (frequency,)) raise AssertionError(f"Unknown frequency: {frequency}")
times = [] times = []
if min_length is not None: if min_length is not None:

View File

@ -26,9 +26,9 @@ def analyze_activity(options: Dict[str, Any]) -> None:
total_duration += duration total_duration += duration
print("%-*s%s" % (37, user_profile.email, duration,)) print("%-*s%s" % (37, user_profile.email, duration,))
print("\nTotal Duration: %s" % (total_duration,)) print(f"\nTotal Duration: {total_duration}")
print("\nTotal Duration in minutes: %s" % (total_duration.total_seconds() / 60.,)) print(f"\nTotal Duration in minutes: {total_duration.total_seconds() / 60.}")
print("Total Duration amortized to a month: %s" % (total_duration.total_seconds() * 30. / 60.,)) print(f"Total Duration amortized to a month: {total_duration.total_seconds() * 30. / 60.}")
class Command(BaseCommand): class Command(BaseCommand):
help = """Report analytics of user activity on a per-user and realm basis. help = """Report analytics of user activity on a per-user and realm basis.

View File

@ -33,8 +33,7 @@ class Command(BaseCommand):
state_file_tmp = state_file_path + "-tmp" state_file_tmp = state_file_path + "-tmp"
with open(state_file_tmp, "w") as f: with open(state_file_tmp, "w") as f:
f.write("%s|%s|%s|%s\n" % ( f.write(f"{int(time.time())}|{status}|{states[status]}|{message}\n")
int(time.time()), status, states[status], message))
os.rename(state_file_tmp, state_file_path) os.rename(state_file_tmp, state_file_path)
def get_fill_state(self) -> Dict[str, Any]: def get_fill_state(self) -> Dict[str, Any]:
@ -50,7 +49,7 @@ class Command(BaseCommand):
try: try:
verify_UTC(last_fill) verify_UTC(last_fill)
except TimezoneNotUTCException: except TimezoneNotUTCException:
return {'status': 2, 'message': 'FillState not in UTC for %s' % (property,)} return {'status': 2, 'message': f'FillState not in UTC for {property}'}
if stat.frequency == CountStat.DAY: if stat.frequency == CountStat.DAY:
floor_function = floor_to_day floor_function = floor_to_day

View File

@ -20,7 +20,7 @@ class Command(BaseCommand):
def handle(self, *args: Any, **options: Any) -> None: def handle(self, *args: Any, **options: Any) -> None:
property = options['property'] property = options['property']
if property not in COUNT_STATS: if property not in COUNT_STATS:
raise CommandError("Invalid property: %s" % (property,)) raise CommandError(f"Invalid property: {property}")
if not options['force']: if not options['force']:
raise CommandError("No action taken. Use --force.") raise CommandError("No action taken. Use --force.")

View File

@ -66,7 +66,7 @@ class Command(BaseCommand):
fraction = 0.0 fraction = 0.0
else: else:
fraction = numerator / float(denominator) fraction = numerator / float(denominator)
print("%.2f%% of" % (fraction * 100,), text) print(f"{fraction * 100:.2f}% of", text)
def handle(self, *args: Any, **options: Any) -> None: def handle(self, *args: Any, **options: Any) -> None:
if options['realms']: if options['realms']:

View File

@ -40,18 +40,18 @@ class Command(BaseCommand):
print("%10s %d public streams and" % ("(", public_count), end=' ') print("%10s %d public streams and" % ("(", public_count), end=' ')
print("%d private streams )" % (private_count,)) print("%d private streams )" % (private_count,))
print("------------") print("------------")
print("%25s %15s %10s %12s" % ("stream", "subscribers", "messages", "type")) print("{:>25} {:>15} {:>10} {:>12}".format("stream", "subscribers", "messages", "type"))
for stream in streams: for stream in streams:
if stream.invite_only: if stream.invite_only:
stream_type = 'private' stream_type = 'private'
else: else:
stream_type = 'public' stream_type = 'public'
print("%25s" % (stream.name,), end=' ') print(f"{stream.name:>25}", end=' ')
recipient = Recipient.objects.filter(type=Recipient.STREAM, type_id=stream.id) recipient = Recipient.objects.filter(type=Recipient.STREAM, type_id=stream.id)
print("%10d" % (len(Subscription.objects.filter(recipient=recipient, print("%10d" % (len(Subscription.objects.filter(recipient=recipient,
active=True)),), end=' ') active=True)),), end=' ')
num_messages = len(Message.objects.filter(recipient=recipient)) num_messages = len(Message.objects.filter(recipient=recipient))
print("%12d" % (num_messages,), end=' ') print("%12d" % (num_messages,), end=' ')
print("%15s" % (stream_type,)) print(f"{stream_type:>15}")
print("") print("")

View File

@ -71,7 +71,7 @@ class Command(BaseCommand):
else: else:
stats = list(COUNT_STATS.values()) stats = list(COUNT_STATS.values())
logger.info("Starting updating analytics counts through %s" % (fill_to_time,)) logger.info(f"Starting updating analytics counts through {fill_to_time}")
if options['verbose']: if options['verbose']:
start = time.time() start = time.time()
last = start last = start
@ -79,13 +79,13 @@ class Command(BaseCommand):
for stat in stats: for stat in stats:
process_count_stat(stat, fill_to_time) process_count_stat(stat, fill_to_time)
if options['verbose']: if options['verbose']:
print("Updated %s in %.3fs" % (stat.property, time.time() - last)) print(f"Updated {stat.property} in {time.time() - last:.3f}s")
last = time.time() last = time.time()
if options['verbose']: if options['verbose']:
print("Finished updating analytics counts through %s in %.3fs" % print("Finished updating analytics counts through %s in %.3fs" %
(fill_to_time, time.time() - start)) (fill_to_time, time.time() - start))
logger.info("Finished updating analytics counts through %s" % (fill_to_time,)) logger.info(f"Finished updating analytics counts through {fill_to_time}")
if settings.PUSH_NOTIFICATION_BOUNCER_URL and settings.SUBMIT_USAGE_STATISTICS: if settings.PUSH_NOTIFICATION_BOUNCER_URL and settings.SUBMIT_USAGE_STATISTICS:
send_analytics_to_remote_server() send_analytics_to_remote_server()

View File

@ -36,7 +36,7 @@ class Command(BaseCommand):
print("%d streams" % (len(Stream.objects.filter(realm=realm)),)) print("%d streams" % (len(Stream.objects.filter(realm=realm)),))
for user_profile in user_profiles: for user_profile in user_profiles:
print("%35s" % (user_profile.email,), end=' ') print(f"{user_profile.email:>35}", end=' ')
for week in range(10): for week in range(10):
print("%5d" % (self.messages_sent_by(user_profile, week),), end=' ') print("%5d" % (self.messages_sent_by(user_profile, week),), end=' ')
print("") print("")

View File

@ -17,7 +17,7 @@ class FillState(models.Model):
state: int = models.PositiveSmallIntegerField() state: int = models.PositiveSmallIntegerField()
def __str__(self) -> str: def __str__(self) -> str:
return "<FillState: %s %s %s>" % (self.property, self.end_time, self.state) return f"<FillState: {self.property} {self.end_time} {self.state}>"
# The earliest/starting end_time in FillState # The earliest/starting end_time in FillState
# We assume there is at least one realm # We assume there is at least one realm
@ -61,7 +61,7 @@ class InstallationCount(BaseCount):
] ]
def __str__(self) -> str: def __str__(self) -> str:
return "<InstallationCount: %s %s %s>" % (self.property, self.subgroup, self.value) return f"<InstallationCount: {self.property} {self.subgroup} {self.value}>"
class RealmCount(BaseCount): class RealmCount(BaseCount):
realm = models.ForeignKey(Realm, on_delete=models.CASCADE) realm = models.ForeignKey(Realm, on_delete=models.CASCADE)
@ -81,7 +81,7 @@ class RealmCount(BaseCount):
index_together = ["property", "end_time"] index_together = ["property", "end_time"]
def __str__(self) -> str: def __str__(self) -> str:
return "<RealmCount: %s %s %s %s>" % (self.realm, self.property, self.subgroup, self.value) return f"<RealmCount: {self.realm} {self.property} {self.subgroup} {self.value}>"
class UserCount(BaseCount): class UserCount(BaseCount):
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE) user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
@ -104,7 +104,7 @@ class UserCount(BaseCount):
index_together = ["property", "realm", "end_time"] index_together = ["property", "realm", "end_time"]
def __str__(self) -> str: def __str__(self) -> str:
return "<UserCount: %s %s %s %s>" % (self.user, self.property, self.subgroup, self.value) return f"<UserCount: {self.user} {self.property} {self.subgroup} {self.value}>"
class StreamCount(BaseCount): class StreamCount(BaseCount):
stream = models.ForeignKey(Stream, on_delete=models.CASCADE) stream = models.ForeignKey(Stream, on_delete=models.CASCADE)
@ -127,5 +127,4 @@ class StreamCount(BaseCount):
index_together = ["property", "realm", "end_time"] index_together = ["property", "realm", "end_time"]
def __str__(self) -> str: def __str__(self) -> str:
return "<StreamCount: %s %s %s %s %s>" % ( return f"<StreamCount: {self.stream} {self.property} {self.subgroup} {self.value} {self.id}>"
self.stream, self.property, self.subgroup, self.value, self.id)

View File

@ -49,7 +49,7 @@ class AnalyticsTestCase(TestCase):
def create_user(self, **kwargs: Any) -> UserProfile: def create_user(self, **kwargs: Any) -> UserProfile:
self.name_counter += 1 self.name_counter += 1
defaults = { defaults = {
'email': 'user%s@domain.tld' % (self.name_counter,), 'email': f'user{self.name_counter}@domain.tld',
'date_joined': self.TIME_LAST_HOUR, 'date_joined': self.TIME_LAST_HOUR,
'full_name': 'full_name', 'full_name': 'full_name',
'short_name': 'short_name', 'short_name': 'short_name',
@ -71,7 +71,7 @@ class AnalyticsTestCase(TestCase):
def create_stream_with_recipient(self, **kwargs: Any) -> Tuple[Stream, Recipient]: def create_stream_with_recipient(self, **kwargs: Any) -> Tuple[Stream, Recipient]:
self.name_counter += 1 self.name_counter += 1
defaults = {'name': 'stream name %s' % (self.name_counter,), defaults = {'name': f'stream name {self.name_counter}',
'realm': self.default_realm, 'realm': self.default_realm,
'date_created': self.TIME_LAST_HOUR} 'date_created': self.TIME_LAST_HOUR}
for key, value in defaults.items(): for key, value in defaults.items():
@ -84,7 +84,7 @@ class AnalyticsTestCase(TestCase):
def create_huddle_with_recipient(self, **kwargs: Any) -> Tuple[Huddle, Recipient]: def create_huddle_with_recipient(self, **kwargs: Any) -> Tuple[Huddle, Recipient]:
self.name_counter += 1 self.name_counter += 1
defaults = {'huddle_hash': 'hash%s' % (self.name_counter,)} defaults = {'huddle_hash': f'hash{self.name_counter}'}
for key, value in defaults.items(): for key, value in defaults.items():
kwargs[key] = kwargs.get(key, value) kwargs[key] = kwargs.get(key, value)
huddle = Huddle.objects.create(**kwargs) huddle = Huddle.objects.create(**kwargs)
@ -339,10 +339,10 @@ class TestCountStats(AnalyticsTestCase):
date_created=self.TIME_ZERO-2*self.DAY) date_created=self.TIME_ZERO-2*self.DAY)
for minutes_ago in [0, 1, 61, 60*24+1]: for minutes_ago in [0, 1, 61, 60*24+1]:
creation_time = self.TIME_ZERO - minutes_ago*self.MINUTE creation_time = self.TIME_ZERO - minutes_ago*self.MINUTE
user = self.create_user(email='user-%s@second.analytics' % (minutes_ago,), user = self.create_user(email=f'user-{minutes_ago}@second.analytics',
realm=self.second_realm, date_joined=creation_time) realm=self.second_realm, date_joined=creation_time)
recipient = self.create_stream_with_recipient( recipient = self.create_stream_with_recipient(
name='stream %s' % (minutes_ago,), realm=self.second_realm, name=f'stream {minutes_ago}', realm=self.second_realm,
date_created=creation_time)[1] date_created=creation_time)[1]
self.create_message(user, recipient, date_sent=creation_time) self.create_message(user, recipient, date_sent=creation_time)
self.hourly_user = get_user('user-1@second.analytics', self.second_realm) self.hourly_user = get_user('user-1@second.analytics', self.second_realm)

View File

@ -408,7 +408,7 @@ class TestSupportEndpoint(ZulipTestCase):
def check_zulip_realm_query_result(result: HttpResponse) -> None: def check_zulip_realm_query_result(result: HttpResponse) -> None:
zulip_realm = get_realm("zulip") zulip_realm = get_realm("zulip")
self.assert_in_success_response(['<input type="hidden" name="realm_id" value="%s"' % (zulip_realm.id,), self.assert_in_success_response([f'<input type="hidden" name="realm_id" value="{zulip_realm.id}"',
'Zulip Dev</h3>', 'Zulip Dev</h3>',
'<option value="1" selected>Self Hosted</option>', '<option value="1" selected>Self Hosted</option>',
'<option value="2" >Limited</option>', '<option value="2" >Limited</option>',
@ -420,7 +420,7 @@ class TestSupportEndpoint(ZulipTestCase):
def check_lear_realm_query_result(result: HttpResponse) -> None: def check_lear_realm_query_result(result: HttpResponse) -> None:
lear_realm = get_realm("lear") lear_realm = get_realm("lear")
self.assert_in_success_response(['<input type="hidden" name="realm_id" value="%s"' % (lear_realm.id,), self.assert_in_success_response([f'<input type="hidden" name="realm_id" value="{lear_realm.id}"',
'Lear &amp; Co.</h3>', 'Lear &amp; Co.</h3>',
'<option value="1" selected>Self Hosted</option>', '<option value="1" selected>Self Hosted</option>',
'<option value="2" >Limited</option>', '<option value="2" >Limited</option>',
@ -532,7 +532,7 @@ class TestSupportEndpoint(ZulipTestCase):
cordelia = self.example_user('cordelia') cordelia = self.example_user('cordelia')
self.login_user(cordelia) self.login_user(cordelia)
result = self.client_post("/activity/support", {"realm_id": "%s" % (cordelia.realm_id,), "plan_type": "2"}) result = self.client_post("/activity/support", {"realm_id": f"{cordelia.realm_id}", "plan_type": "2"})
self.assertEqual(result.status_code, 302) self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], "/login/") self.assertEqual(result["Location"], "/login/")
@ -540,7 +540,7 @@ class TestSupportEndpoint(ZulipTestCase):
self.login_user(iago) self.login_user(iago)
with mock.patch("analytics.views.do_change_plan_type") as m: with mock.patch("analytics.views.do_change_plan_type") as m:
result = self.client_post("/activity/support", {"realm_id": "%s" % (iago.realm_id,), "plan_type": "2"}) result = self.client_post("/activity/support", {"realm_id": f"{iago.realm_id}", "plan_type": "2"})
m.assert_called_once_with(get_realm("zulip"), 2) m.assert_called_once_with(get_realm("zulip"), 2)
self.assert_in_success_response(["Plan type of Zulip Dev changed from self hosted to limited"], result) self.assert_in_success_response(["Plan type of Zulip Dev changed from self hosted to limited"], result)
@ -549,14 +549,14 @@ class TestSupportEndpoint(ZulipTestCase):
lear_realm = get_realm('lear') lear_realm = get_realm('lear')
self.login_user(cordelia) self.login_user(cordelia)
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "discount": "25"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "discount": "25"})
self.assertEqual(result.status_code, 302) self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], "/login/") self.assertEqual(result["Location"], "/login/")
self.login('iago') self.login('iago')
with mock.patch("analytics.views.attach_discount_to_realm") as m: with mock.patch("analytics.views.attach_discount_to_realm") as m:
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "discount": "25"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "discount": "25"})
m.assert_called_once_with(get_realm("lear"), 25) m.assert_called_once_with(get_realm("lear"), 25)
self.assert_in_success_response(["Discount of Lear &amp; Co. changed to 25 from None"], result) self.assert_in_success_response(["Discount of Lear &amp; Co. changed to 25 from None"], result)
@ -565,19 +565,19 @@ class TestSupportEndpoint(ZulipTestCase):
lear_realm = get_realm('lear') lear_realm = get_realm('lear')
self.login_user(cordelia) self.login_user(cordelia)
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "status": "deactivated"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "status": "deactivated"})
self.assertEqual(result.status_code, 302) self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], "/login/") self.assertEqual(result["Location"], "/login/")
self.login('iago') self.login('iago')
with mock.patch("analytics.views.do_deactivate_realm") as m: with mock.patch("analytics.views.do_deactivate_realm") as m:
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "status": "deactivated"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "status": "deactivated"})
m.assert_called_once_with(lear_realm, self.example_user("iago")) m.assert_called_once_with(lear_realm, self.example_user("iago"))
self.assert_in_success_response(["Lear &amp; Co. deactivated"], result) self.assert_in_success_response(["Lear &amp; Co. deactivated"], result)
with mock.patch("analytics.views.do_send_realm_reactivation_email") as m: with mock.patch("analytics.views.do_send_realm_reactivation_email") as m:
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "status": "active"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "status": "active"})
m.assert_called_once_with(lear_realm) m.assert_called_once_with(lear_realm)
self.assert_in_success_response(["Realm reactivation email sent to admins of Lear"], result) self.assert_in_success_response(["Realm reactivation email sent to admins of Lear"], result)
@ -586,19 +586,19 @@ class TestSupportEndpoint(ZulipTestCase):
lear_realm = get_realm('lear') lear_realm = get_realm('lear')
self.login_user(cordelia) self.login_user(cordelia)
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "discount": "25"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "discount": "25"})
self.assertEqual(result.status_code, 302) self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], "/login/") self.assertEqual(result["Location"], "/login/")
self.login('iago') self.login('iago')
with mock.patch("analytics.views.do_scrub_realm") as m: with mock.patch("analytics.views.do_scrub_realm") as m:
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,), "scrub_realm": "scrub_realm"}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}", "scrub_realm": "scrub_realm"})
m.assert_called_once_with(lear_realm) m.assert_called_once_with(lear_realm)
self.assert_in_success_response(["Lear &amp; Co. scrubbed"], result) self.assert_in_success_response(["Lear &amp; Co. scrubbed"], result)
with mock.patch("analytics.views.do_scrub_realm") as m: with mock.patch("analytics.views.do_scrub_realm") as m:
result = self.client_post("/activity/support", {"realm_id": "%s" % (lear_realm.id,)}) result = self.client_post("/activity/support", {"realm_id": f"{lear_realm.id}"})
m.assert_not_called() m.assert_not_called()
class TestGetChartDataHelpers(ZulipTestCase): class TestGetChartDataHelpers(ZulipTestCase):

View File

@ -96,9 +96,9 @@ def stats_for_realm(request: HttpRequest, realm_str: str) -> HttpResponse:
try: try:
realm = get_realm(realm_str) realm = get_realm(realm_str)
except Realm.DoesNotExist: except Realm.DoesNotExist:
return HttpResponseNotFound("Realm %s does not exist" % (realm_str,)) return HttpResponseNotFound(f"Realm {realm_str} does not exist")
return render_stats(request, '/realm/%s' % (realm_str,), realm.name or realm.string_id, return render_stats(request, f'/realm/{realm_str}', realm.name or realm.string_id,
analytics_ready=is_analytics_ready(realm)) analytics_ready=is_analytics_ready(realm))
@require_server_admin @require_server_admin
@ -106,8 +106,8 @@ def stats_for_realm(request: HttpRequest, realm_str: str) -> HttpResponse:
def stats_for_remote_realm(request: HttpRequest, remote_server_id: str, def stats_for_remote_realm(request: HttpRequest, remote_server_id: str,
remote_realm_id: str) -> HttpResponse: remote_realm_id: str) -> HttpResponse:
server = RemoteZulipServer.objects.get(id=remote_server_id) server = RemoteZulipServer.objects.get(id=remote_server_id)
return render_stats(request, '/remote/%s/realm/%s' % (server.id, remote_realm_id), return render_stats(request, f'/remote/{server.id}/realm/{remote_realm_id}',
"Realm %s on server %s" % (remote_realm_id, server.hostname)) f"Realm {remote_realm_id} on server {server.hostname}")
@require_server_admin_api @require_server_admin_api
@has_request_variables @has_request_variables
@ -136,8 +136,8 @@ def stats_for_installation(request: HttpRequest) -> HttpResponse:
@require_server_admin @require_server_admin
def stats_for_remote_installation(request: HttpRequest, remote_server_id: str) -> HttpResponse: def stats_for_remote_installation(request: HttpRequest, remote_server_id: str) -> HttpResponse:
server = RemoteZulipServer.objects.get(id=remote_server_id) server = RemoteZulipServer.objects.get(id=remote_server_id)
return render_stats(request, '/remote/%s/installation' % (server.id,), return render_stats(request, f'/remote/{server.id}/installation',
'remote Installation %s' % (server.hostname,), True, True) f'remote Installation {server.hostname}', True, True)
@require_server_admin_api @require_server_admin_api
@has_request_variables @has_request_variables
@ -332,7 +332,7 @@ def table_filtered_to_id(table: Type[BaseCount], key_id: int) -> QuerySet:
elif table == RemoteRealmCount: elif table == RemoteRealmCount:
return RemoteRealmCount.objects.filter(realm_id=key_id) return RemoteRealmCount.objects.filter(realm_id=key_id)
else: else:
raise AssertionError("Unknown table: %s" % (table,)) raise AssertionError(f"Unknown table: {table}")
def client_label_map(name: str) -> str: def client_label_map(name: str) -> str:
if name == "website": if name == "website":
@ -463,7 +463,7 @@ def get_realm_day_counts() -> Dict[str, Dict[str, str]]:
else: else:
good_bad = 'neutral' good_bad = 'neutral'
return '<td class="number %s">%s</td>' % (good_bad, cnt) return f'<td class="number {good_bad}">{cnt}</td>'
cnts = (format_count(raw_cnts[0], 'neutral') cnts = (format_count(raw_cnts[0], 'neutral')
+ ''.join(map(format_count, raw_cnts[1:]))) + ''.join(map(format_count, raw_cnts[1:])))
@ -629,7 +629,7 @@ def realm_summary_table(realm_minutes: Dict[str, float]) -> str:
total_hours += hours total_hours += hours
row['hours'] = str(int(hours)) row['hours'] = str(int(hours))
try: try:
row['hours_per_user'] = '%.1f' % (hours / row['dau_count'],) row['hours_per_user'] = '{:.1f}'.format(hours / row['dau_count'])
except Exception: except Exception:
pass pass
@ -709,7 +709,7 @@ def user_activity_intervals() -> Tuple[mark_safe, Dict[str, float]]:
for string_id, realm_intervals in itertools.groupby(all_intervals, by_string_id): for string_id, realm_intervals in itertools.groupby(all_intervals, by_string_id):
realm_duration = timedelta(0) realm_duration = timedelta(0)
output += '<hr>%s\n' % (string_id,) output += f'<hr>{string_id}\n'
for email, intervals in itertools.groupby(realm_intervals, by_email): for email, intervals in itertools.groupby(realm_intervals, by_email):
duration = timedelta(0) duration = timedelta(0)
for interval in intervals: for interval in intervals:
@ -723,9 +723,9 @@ def user_activity_intervals() -> Tuple[mark_safe, Dict[str, float]]:
realm_minutes[string_id] = realm_duration.total_seconds() / 60 realm_minutes[string_id] = realm_duration.total_seconds() / 60
output += "\nTotal Duration: %s\n" % (total_duration,) output += f"\nTotal Duration: {total_duration}\n"
output += "\nTotal Duration in minutes: %s\n" % (total_duration.total_seconds() / 60.,) output += f"\nTotal Duration in minutes: {total_duration.total_seconds() / 60.}\n"
output += "Total Duration amortized to a month: %s" % (total_duration.total_seconds() * 30. / 60.,) output += f"Total Duration amortized to a month: {total_duration.total_seconds() * 30. / 60.}"
content = mark_safe('<pre>' + output + '</pre>') content = mark_safe('<pre>' + output + '</pre>')
return content, realm_minutes return content, realm_minutes
@ -841,7 +841,7 @@ def ad_hoc_queries() -> List[Dict[str, str]]:
### ###
for mobile_type in ['Android', 'ZulipiOS']: for mobile_type in ['Android', 'ZulipiOS']:
title = '%s usage' % (mobile_type,) title = f'{mobile_type} usage'
query = SQL(''' query = SQL('''
select select
@ -1284,13 +1284,13 @@ def format_date_for_activity_reports(date: Optional[datetime]) -> str:
def user_activity_link(email: str) -> mark_safe: def user_activity_link(email: str) -> mark_safe:
url_name = 'analytics.views.get_user_activity' url_name = 'analytics.views.get_user_activity'
url = reverse(url_name, kwargs=dict(email=email)) url = reverse(url_name, kwargs=dict(email=email))
email_link = '<a href="%s">%s</a>' % (url, email) email_link = f'<a href="{url}">{email}</a>'
return mark_safe(email_link) return mark_safe(email_link)
def realm_activity_link(realm_str: str) -> mark_safe: def realm_activity_link(realm_str: str) -> mark_safe:
url_name = 'analytics.views.get_realm_activity' url_name = 'analytics.views.get_realm_activity'
url = reverse(url_name, kwargs=dict(realm_str=realm_str)) url = reverse(url_name, kwargs=dict(realm_str=realm_str))
realm_link = '<a href="%s">%s</a>' % (url, realm_str) realm_link = f'<a href="{url}">{realm_str}</a>'
return mark_safe(realm_link) return mark_safe(realm_link)
def realm_stats_link(realm_str: str) -> mark_safe: def realm_stats_link(realm_str: str) -> mark_safe:
@ -1449,7 +1449,7 @@ def get_realm_activity(request: HttpRequest, realm_str: str) -> HttpResponse:
try: try:
admins = Realm.objects.get(string_id=realm_str).get_human_admin_users() admins = Realm.objects.get(string_id=realm_str).get_human_admin_users()
except Realm.DoesNotExist: except Realm.DoesNotExist:
return HttpResponseNotFound("Realm %s does not exist" % (realm_str,)) return HttpResponseNotFound(f"Realm {realm_str} does not exist")
admin_emails = {admin.delivery_email for admin in admins} admin_emails = {admin.delivery_email for admin in admins}

View File

@ -185,7 +185,7 @@ def do_create_stripe_customer(user: UserProfile, stripe_token: Optional[str]=Non
# bad thing that will happen is that we will create an extra stripe # bad thing that will happen is that we will create an extra stripe
# customer that we can delete or ignore. # customer that we can delete or ignore.
stripe_customer = stripe.Customer.create( stripe_customer = stripe.Customer.create(
description="%s (%s)" % (realm.string_id, realm.name), description=f"{realm.string_id} ({realm.name})",
email=user.delivery_email, email=user.delivery_email,
metadata={'realm_id': realm.id, 'realm_str': realm.string_id}, metadata={'realm_id': realm.id, 'realm_str': realm.string_id},
source=stripe_token) source=stripe_token)

View File

@ -14,7 +14,7 @@ class Customer(models.Model):
default_discount: Optional[Decimal] = models.DecimalField(decimal_places=4, max_digits=7, null=True) default_discount: Optional[Decimal] = models.DecimalField(decimal_places=4, max_digits=7, null=True)
def __str__(self) -> str: def __str__(self) -> str:
return "<Customer %s %s>" % (self.realm, self.stripe_customer_id) return f"<Customer {self.realm} {self.stripe_customer_id}>"
def get_customer_by_realm(realm: Realm) -> Optional[Customer]: def get_customer_by_realm(realm: Realm) -> Optional[Customer]:
return Customer.objects.filter(realm=realm).first() return Customer.objects.filter(realm=realm).first()

View File

@ -144,7 +144,7 @@ def normalize_fixture_data(decorated_function: CallableT,
for i, timestamp_field in enumerate(tested_timestamp_fields): for i, timestamp_field in enumerate(tested_timestamp_fields):
# Don't use (..) notation, since the matched timestamp can easily appear in other fields # Don't use (..) notation, since the matched timestamp can easily appear in other fields
pattern_translations[ pattern_translations[
'"%s": 1[5-9][0-9]{8}(?![0-9-])' % (timestamp_field,) f'"{timestamp_field}": 1[5-9][0-9]{{8}}(?![0-9-])'
] = '"%s": 1%02d%%07d' % (timestamp_field, i+1) ] = '"%s": 1%02d%%07d' % (timestamp_field, i+1)
normalized_values: Dict[str, Dict[str, str]] = { normalized_values: Dict[str, Dict[str, str]] = {
@ -463,8 +463,8 @@ class StripeTest(StripeTestCase):
self.assert_not_in_success_response(['Pay annually'], response) self.assert_not_in_success_response(['Pay annually'], response)
for substring in [ for substring in [
'Zulip Standard', str(self.seat_count), 'Zulip Standard', str(self.seat_count),
'You are using', '%s of %s licenses' % (self.seat_count, self.seat_count), 'You are using', f'{self.seat_count} of {self.seat_count} licenses',
'Your plan will renew on', 'January 2, 2013', '$%s.00' % (80 * self.seat_count,), 'Your plan will renew on', 'January 2, 2013', f'${80 * self.seat_count}.00',
'Visa ending in 4242', 'Visa ending in 4242',
'Update card']: 'Update card']:
self.assert_in_response(substring, response) self.assert_in_response(substring, response)
@ -547,7 +547,7 @@ class StripeTest(StripeTestCase):
self.assert_not_in_success_response(['Pay annually', 'Update card'], response) self.assert_not_in_success_response(['Pay annually', 'Update card'], response)
for substring in [ for substring in [
'Zulip Standard', str(123), 'Zulip Standard', str(123),
'You are using', '%s of %s licenses' % (self.seat_count, 123), 'You are using', f'{self.seat_count} of {123} licenses',
'Your plan will renew on', 'January 2, 2013', '$9,840.00', # 9840 = 80 * 123 'Your plan will renew on', 'January 2, 2013', '$9,840.00', # 9840 = 80 * 123
'Billed by invoice']: 'Billed by invoice']:
self.assert_in_response(substring, response) self.assert_in_response(substring, response)
@ -618,8 +618,8 @@ class StripeTest(StripeTestCase):
self.assert_not_in_success_response(['Pay annually'], response) self.assert_not_in_success_response(['Pay annually'], response)
for substring in [ for substring in [
'Zulip Standard', 'Free Trial', str(self.seat_count), 'Zulip Standard', 'Free Trial', str(self.seat_count),
'You are using', '%s of %s licenses' % (self.seat_count, self.seat_count), 'You are using', f'{self.seat_count} of {self.seat_count} licenses',
'Your plan will be upgraded to', 'March 2, 2012', '$%s.00' % (80 * self.seat_count,), 'Your plan will be upgraded to', 'March 2, 2012', f'${80 * self.seat_count}.00',
'Visa ending in 4242', 'Visa ending in 4242',
'Update card']: 'Update card']:
self.assert_in_response(substring, response) self.assert_in_response(substring, response)
@ -772,7 +772,7 @@ class StripeTest(StripeTestCase):
self.assert_not_in_success_response(['Pay annually'], response) self.assert_not_in_success_response(['Pay annually'], response)
for substring in [ for substring in [
'Zulip Standard', 'Free Trial', str(self.seat_count), 'Zulip Standard', 'Free Trial', str(self.seat_count),
'You are using', '%s of %s licenses' % (self.seat_count, 123), 'You are using', f'{self.seat_count} of {123} licenses',
'Your plan will be upgraded to', 'March 2, 2012', 'Your plan will be upgraded to', 'March 2, 2012',
f'{80 * 123:,.2f}', 'Billed by invoice' f'{80 * 123:,.2f}', 'Billed by invoice'
]: ]:

View File

@ -114,7 +114,7 @@ def upgrade(request: HttpRequest, user: UserProfile,
) )
return json_error(e.message, data={'error_description': e.description}) return json_error(e.message, data={'error_description': e.description})
except Exception as e: except Exception as e:
billing_logger.exception("Uncaught exception in billing: %s" % (e,)) billing_logger.exception(f"Uncaught exception in billing: {e}")
error_message = BillingError.CONTACT_SUPPORT error_message = BillingError.CONTACT_SUPPORT
error_description = "uncaught exception during upgrade" error_description = "uncaught exception during upgrade"
return json_error(error_message, data={'error_description': error_description}) return json_error(error_message, data={'error_description': error_description})

View File

@ -121,7 +121,7 @@ def run_tests(files: Iterable[str], external_host: str) -> None:
for test_file in test_files: for test_file in test_files:
test_name = os.path.basename(test_file) test_name = os.path.basename(test_file)
cmd = ["node_modules/.bin/casperjs"] + remote_debug + verbose + xunit_export + ["test", test_file] cmd = ["node_modules/.bin/casperjs"] + remote_debug + verbose + xunit_export + ["test", test_file]
print("\n\n===================== %s\nRunning %s\n\n" % (test_name, " ".join(map(shlex.quote, cmd))), flush=True) print("\n\n===================== {}\nRunning {}\n\n".format(test_name, " ".join(map(shlex.quote, cmd))), flush=True)
ret = subprocess.call(cmd) ret = subprocess.call(cmd)
if ret != 0: if ret != 0:
return ret return ret

View File

@ -36,7 +36,7 @@ def nagios_from_file(results_file: str, max_time_diff: int=60 * 2) -> 'Tuple[int
state = pieces[2] state = pieces[2]
data = pieces[3] data = pieces[3]
return (ret, "%s: %s" % (state, data)) return (ret, f"{state}: {data}")
if __name__ == "__main__": if __name__ == "__main__":
RESULTS_FILE = sys.argv[1] RESULTS_FILE = sys.argv[1]

View File

@ -12,7 +12,7 @@ import sys
wildcard = os.path.join("/var/log/zulip/queue_error", '*.errors') wildcard = os.path.join("/var/log/zulip/queue_error", '*.errors')
clean = True clean = True
for fn in glob.glob(wildcard): for fn in glob.glob(wildcard):
print('WARNING: Queue errors logged in %s' % (fn,)) print(f'WARNING: Queue errors logged in {fn}')
clean = False clean = False
if not clean: if not clean:

View File

@ -17,7 +17,7 @@ if len(sys.argv) < 2:
print("Please pass the name of the consumer file to check") print("Please pass the name of the consumer file to check")
exit(1) exit(1)
RESULTS_FILE = "/var/lib/nagios_state/check-rabbitmq-consumers-%s" % (sys.argv[1],) RESULTS_FILE = f"/var/lib/nagios_state/check-rabbitmq-consumers-{sys.argv[1]}"
ret, result = nagios_from_file(RESULTS_FILE) ret, result = nagios_from_file(RESULTS_FILE)

View File

@ -88,24 +88,24 @@ states = {
def report(state: str, timestamp: Any = None, msg: Optional[str] = None) -> None: def report(state: str, timestamp: Any = None, msg: Optional[str] = None) -> None:
now = int(time.time()) now = int(time.time())
if msg is None: if msg is None:
msg = "send time was %s" % (timestamp,) msg = f"send time was {timestamp}"
state_file_path = "/var/lib/nagios_state/check_send_receive_state" state_file_path = "/var/lib/nagios_state/check_send_receive_state"
with open(state_file_path + ".tmp", 'w') as f: with open(state_file_path + ".tmp", 'w') as f:
f.write("%s|%s|%s|%s\n" % (now, states[state], state, msg)) f.write(f"{now}|{states[state]}|{state}|{msg}\n")
os.rename(state_file_path + ".tmp", state_file_path) os.rename(state_file_path + ".tmp", state_file_path)
print("%s: %s" % (state, msg)) print(f"{state}: {msg}")
exit(states[state]) exit(states[state])
def send_zulip(sender: zulip.Client, message: Dict[str, Any]) -> None: def send_zulip(sender: zulip.Client, message: Dict[str, Any]) -> None:
result = sender.send_message(message) result = sender.send_message(message)
if result["result"] != "success" and options.nagios: if result["result"] != "success" and options.nagios:
report("CRITICAL", msg="Error sending Zulip, args were: %s, %s" % (message, result)) report("CRITICAL", msg=f"Error sending Zulip, args were: {message}, {result}")
def get_zulips() -> List[Dict[str, Any]]: def get_zulips() -> List[Dict[str, Any]]:
global queue_id, last_event_id global queue_id, last_event_id
res = zulip_recipient.get_events(queue_id=queue_id, last_event_id=last_event_id) res = zulip_recipient.get_events(queue_id=queue_id, last_event_id=last_event_id)
if 'error' in res.get('result', {}): if 'error' in res.get('result', {}):
report("CRITICAL", msg="Error receiving Zulips, error was: %s" % (res["msg"],)) report("CRITICAL", msg="Error receiving Zulips, error was: {}".format(res["msg"]))
for event in res['events']: for event in res['events']:
last_event_id = max(last_event_id, int(event['id'])) last_event_id = max(last_event_id, int(event['id']))
# If we get a heartbeat event, that means we've been hanging for # If we get a heartbeat event, that means we've been hanging for
@ -141,10 +141,10 @@ zulip_recipient = zulip.Client(
try: try:
res = zulip_recipient.register(event_types=["message"]) res = zulip_recipient.register(event_types=["message"])
if 'error' in res.get('result', {}): if 'error' in res.get('result', {}):
report("CRITICAL", msg="Error subscribing to Zulips: %s" % (res['msg'],)) report("CRITICAL", msg="Error subscribing to Zulips: {}".format(res['msg']))
queue_id, last_event_id = (res['queue_id'], res['last_event_id']) queue_id, last_event_id = (res['queue_id'], res['last_event_id'])
except Exception: except Exception:
report("CRITICAL", msg="Error subscribing to Zulips:\n%s" % (traceback.format_exc(),)) report("CRITICAL", msg=f"Error subscribing to Zulips:\n{traceback.format_exc()}")
msg_to_send = str(random.getrandbits(64)) msg_to_send = str(random.getrandbits(64))
time_start = time.time() time_start = time.time()
@ -172,6 +172,6 @@ if options.nagios:
report('WARNING', timestamp=seconds_diff) report('WARNING', timestamp=seconds_diff)
if options.munin: if options.munin:
print("sendreceive.value %s" % (seconds_diff,)) print(f"sendreceive.value {seconds_diff}")
elif options.nagios: elif options.nagios:
report('OK', timestamp=seconds_diff) report('OK', timestamp=seconds_diff)

View File

@ -22,17 +22,17 @@ states = {
} }
def report(state: str, msg: str) -> "NoReturn": def report(state: str, msg: str) -> "NoReturn":
print("%s: %s" % (state, msg)) print(f"{state}: {msg}")
exit(states[state]) exit(states[state])
def get_loc_over_ssh(host: str, func: str) -> str: def get_loc_over_ssh(host: str, func: str) -> str:
try: try:
return subprocess.check_output(['ssh', host, return subprocess.check_output(['ssh', host,
'psql -v ON_ERROR_STOP=1 zulip -t -c "SELECT %s()"' % (func,)], f'psql -v ON_ERROR_STOP=1 zulip -t -c "SELECT {func}()"'],
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
universal_newlines=True) universal_newlines=True)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
report('CRITICAL', 'ssh failed: %s: %s' % (str(e), e.output)) report('CRITICAL', f'ssh failed: {str(e)}: {e.output}')
def loc_to_abs_offset(loc_str: str) -> int: def loc_to_abs_offset(loc_str: str) -> int:
m = re.match(r'^\s*([0-9a-fA-F]+)/([0-9a-fA-F]+)\s*$', loc_str) m = re.match(r'^\s*([0-9a-fA-F]+)/([0-9a-fA-F]+)\s*$', loc_str)

View File

@ -22,7 +22,7 @@ states = {
} }
def report(state: str, num: str) -> None: def report(state: str, num: str) -> None:
print("%s: %s rows in fts_update_log table" % (state, num)) print(f"{state}: {num} rows in fts_update_log table")
exit(states[state]) exit(states[state])
conn = psycopg2.connect(database="zulip") conn = psycopg2.connect(database="zulip")

View File

@ -13,7 +13,7 @@ states = {
} }
def report(state: str, msg: str) -> None: def report(state: str, msg: str) -> None:
print("%s: %s" % (state, msg)) print(f"{state}: {msg}")
exit(states[state]) exit(states[state])
if subprocess.check_output(['psql', '-v', 'ON_ERROR_STOP=1', if subprocess.check_output(['psql', '-v', 'ON_ERROR_STOP=1',
@ -28,6 +28,6 @@ except OSError:
report('UNKNOWN', 'could not determine completion time of last Postgres backup') report('UNKNOWN', 'could not determine completion time of last Postgres backup')
if datetime.now(tz=timezone.utc) - last_backup > timedelta(hours=25): if datetime.now(tz=timezone.utc) - last_backup > timedelta(hours=25):
report('CRITICAL', 'last Postgres backup completed more than 25 hours ago: %s' % (last_backup,)) report('CRITICAL', f'last Postgres backup completed more than 25 hours ago: {last_backup}')
report('OK', 'last Postgres backup completed less than 25 hours ago: %s' % (last_backup,)) report('OK', f'last Postgres backup completed less than 25 hours ago: {last_backup}')

View File

@ -42,7 +42,7 @@ if is_rhel_based:
else: else:
pg_data_paths = glob.glob('/var/lib/postgresql/*/main') pg_data_paths = glob.glob('/var/lib/postgresql/*/main')
if len(pg_data_paths) != 1: if len(pg_data_paths) != 1:
print("Postgres installation is not unique: %s" % (pg_data_paths,)) print(f"Postgres installation is not unique: {pg_data_paths}")
sys.exit(1) sys.exit(1)
pg_data_path = pg_data_paths[0] pg_data_path = pg_data_paths[0]
run(['env-wal-e', 'backup-push', pg_data_path]) run(['env-wal-e', 'backup-push', pg_data_path])

View File

@ -142,7 +142,7 @@ while True:
# Catch up on any historical columns # Catch up on any historical columns
while True: while True:
rows_updated = update_fts_columns(cursor) rows_updated = update_fts_columns(cursor)
notice = "Processed %s rows catching up" % (rows_updated,) notice = f"Processed {rows_updated} rows catching up"
if rows_updated > 0: if rows_updated > 0:
logger.info(notice) logger.info(notice)
else: else:

View File

@ -22,7 +22,7 @@ states: Dict[str, int] = {
} }
def report(state: str, output: str) -> None: def report(state: str, output: str) -> None:
print("%s\n%s" % (state, output)) print(f"{state}\n{output}")
exit(states[state]) exit(states[state])
output = "" output = ""
@ -41,7 +41,7 @@ for results_file_name in os.listdir(RESULTS_DIR):
down_count += 1 down_count += 1
this_state = "DOWN" this_state = "DOWN"
last_check_ts = time.strftime("%Y-%m-%d %H:%M %Z", time.gmtime(last_check)) last_check_ts = time.strftime("%Y-%m-%d %H:%M %Z", time.gmtime(last_check))
output += "%s: %s (%s)\n" % (results_file, this_state, last_check_ts) output += f"{results_file}: {this_state} ({last_check_ts})\n"
if down_count == 0: if down_count == 0:
state = "OK" state = "OK"

View File

@ -39,11 +39,11 @@ def report(state: str, short_msg: str, too_old: Optional[Set[Any]] = None) -> No
too_old_data = "" too_old_data = ""
if too_old: if too_old:
too_old_data = "\nLast call to get_message for recently out of date mirrors:\n" + "\n".join( too_old_data = "\nLast call to get_message for recently out of date mirrors:\n" + "\n".join(
["%16s: %s" % (user.user_profile.email, ["{:>16}: {}".format(user.user_profile.email,
user.last_visit.strftime("%Y-%m-%d %H:%M %Z") user.last_visit.strftime("%Y-%m-%d %H:%M %Z")
) for user in too_old] ) for user in too_old]
) )
print("%s: %s%s" % (state, short_msg, too_old_data)) print(f"{state}: {short_msg}{too_old_data}")
exit(states[state]) exit(states[state])

View File

@ -23,7 +23,7 @@ states: Dict[str, int] = {
} }
def report(state: str, data: str, last_check: float) -> None: def report(state: str, data: str, last_check: float) -> None:
print("%s: Last test run completed at %s\n%s" % ( print("{}: Last test run completed at {}\n{}".format(
state, time.strftime("%Y-%m-%d %H:%M %Z", time.gmtime(last_check)), state, time.strftime("%Y-%m-%d %H:%M %Z", time.gmtime(last_check)),
data)) data))
exit(states[state]) exit(states[state])

View File

@ -131,7 +131,7 @@ for device in macs.values():
for (count, ip) in enumerate(to_configure): for (count, ip) in enumerate(to_configure):
# Configure the IP via a virtual interface # Configure the IP via a virtual interface
device = "ens%i:%i" % (device_number, count) device = "ens%i:%i" % (device_number, count)
log.info("Configuring %s with IP %s" % (device, ip)) log.info(f"Configuring {device} with IP {ip}")
subprocess.check_call(['/sbin/ifconfig', device, ip]) subprocess.check_call(['/sbin/ifconfig', device, ip])
subprocess.check_call( subprocess.check_call(
['/sbin/iptables', '-t', 'mangle', '-A', 'OUTPUT', '-m', 'conntrack', '--ctorigdst', ['/sbin/iptables', '-t', 'mangle', '-A', 'OUTPUT', '-m', 'conntrack', '--ctorigdst',

View File

@ -77,7 +77,7 @@ def analyze_queue_stats(queue_name: str, stats: Dict[str, Any],
# 50). # 50).
return dict(status=CRITICAL, return dict(status=CRITICAL,
name=queue_name, name=queue_name,
message='queue appears to be stuck, last update %s, queue size %s' % ( message='queue appears to be stuck, last update {}, queue size {}'.format(
stats['update_time'], queue_count_rabbitmqctl)) stats['update_time'], queue_count_rabbitmqctl))
current_size = stats['current_queue_size'] current_size = stats['current_queue_size']
@ -108,8 +108,7 @@ def analyze_queue_stats(queue_name: str, stats: Dict[str, Any],
return dict(status=status, return dict(status=status,
name=queue_name, name=queue_name,
message='clearing the backlog will take too long: %ss, size: %s' % ( message=f'clearing the backlog will take too long: {expected_time_to_clear_backlog}s, size: {current_size}')
expected_time_to_clear_backlog, current_size))
else: else:
# We slept recently, so treat this as a burst. # We slept recently, so treat this as a burst.
if expected_time_to_clear_backlog > MAX_SECONDS_TO_CLEAR_FOR_BURSTS[queue_name]: if expected_time_to_clear_backlog > MAX_SECONDS_TO_CLEAR_FOR_BURSTS[queue_name]:
@ -120,8 +119,7 @@ def analyze_queue_stats(queue_name: str, stats: Dict[str, Any],
return dict(status=status, return dict(status=status,
name=queue_name, name=queue_name,
message='clearing the burst will take too long: %ss, size: %s' % ( message=f'clearing the burst will take too long: {expected_time_to_clear_backlog}s, size: {current_size}')
expected_time_to_clear_backlog, current_size))
return dict(status=OK, return dict(status=OK,
name=queue_name, name=queue_name,
@ -139,10 +137,10 @@ def check_other_queues(queue_counts_dict: Dict[str, int]) -> List[Dict[str, Any]
if count > CRITICAL_COUNT_THRESHOLD_DEFAULT: if count > CRITICAL_COUNT_THRESHOLD_DEFAULT:
results.append(dict(status=CRITICAL, name=queue, results.append(dict(status=CRITICAL, name=queue,
message='count critical: %s' % (count,))) message=f'count critical: {count}'))
elif count > WARN_COUNT_THRESHOLD_DEFAULT: elif count > WARN_COUNT_THRESHOLD_DEFAULT:
results.append(dict(status=WARNING, name=queue, results.append(dict(status=WARNING, name=queue,
message='count warning: %s' % (count,))) message=f'count warning: {count}'))
else: else:
results.append(dict(status=OK, name=queue, message='')) results.append(dict(status=OK, name=queue, message=''))
@ -210,6 +208,6 @@ def check_rabbitmq_queues() -> None:
queue_error_template.format(result['name'], states[result['status']], result['message']) queue_error_template.format(result['name'], states[result['status']], result['message'])
for result in results if result['status'] > 0 for result in results if result['status'] > 0
]) ])
print("%s|%s|%s|%s" % (now, status, states[status], error_message)) print(f"{now}|{status}|{states[status]}|{error_message}")
else: else:
print("%s|%s|%s|queues normal" % (now, status, states[status])) print(f"{now}|{status}|{states[status]}|queues normal")

View File

@ -15,9 +15,9 @@ setup_path()
from scripts.lib.zulip_tools import get_config_file from scripts.lib.zulip_tools import get_config_file
def write_realm_nginx_config_line(f: Any, host: str, port: str) -> None: def write_realm_nginx_config_line(f: Any, host: str, port: str) -> None:
f.write("""if ($host = '%s') { f.write("""if ($host = '{}') {{
set $tornado_server http://tornado%s; set $tornado_server http://tornado{};
}\n""" % (host, port)) }}\n""".format(host, port))
# Basic system to do Tornado sharding. Writes two output .tmp files that need # Basic system to do Tornado sharding. Writes two output .tmp files that need
# to be renamed to the following files to finalize the changes: # to be renamed to the following files to finalize the changes:
@ -48,7 +48,7 @@ with open('/etc/zulip/nginx_sharding.conf.tmp', 'w') as nginx_sharding_conf_f, \
host = shard host = shard
else: else:
host = f"{shard}.{external_host}" host = f"{shard}.{external_host}"
assert host not in shard_map, "host %s duplicated" % (host,) assert host not in shard_map, f"host {host} duplicated"
shard_map[host] = int(port) shard_map[host] = int(port)
write_realm_nginx_config_line(nginx_sharding_conf_f, host, port) write_realm_nginx_config_line(nginx_sharding_conf_f, host, port)
nginx_sharding_conf_f.write('\n') nginx_sharding_conf_f.write('\n')

View File

@ -14,7 +14,7 @@ from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, ENDC, make_deploy_pat
import version import version
if len(sys.argv) != 2: if len(sys.argv) != 2:
print(FAIL + "Usage: %s <tarball>" % (sys.argv[0],) + ENDC) print(FAIL + f"Usage: {sys.argv[0]} <tarball>" + ENDC)
sys.exit(1) sys.exit(1)
tarball_path = sys.argv[1] tarball_path = sys.argv[1]

View File

@ -28,12 +28,12 @@ logging.basicConfig(format="%(asctime)s upgrade-zulip: %(message)s",
level=logging.INFO) level=logging.INFO)
if len(sys.argv) != 2: if len(sys.argv) != 2:
print(FAIL + "Usage: %s <tarball>" % (sys.argv[0],) + ENDC) print(FAIL + f"Usage: {sys.argv[0]} <tarball>" + ENDC)
sys.exit(1) sys.exit(1)
tarball_path = sys.argv[1] tarball_path = sys.argv[1]
error_rerun_script = "%s/current/scripts/upgrade-zulip %s" % (DEPLOYMENTS_DIR, tarball_path) error_rerun_script = f"{DEPLOYMENTS_DIR}/current/scripts/upgrade-zulip {tarball_path}"
get_deployment_lock(error_rerun_script) get_deployment_lock(error_rerun_script)
try: try:

View File

@ -42,7 +42,7 @@ if args.remote_url:
os.makedirs(DEPLOYMENTS_DIR, exist_ok=True) os.makedirs(DEPLOYMENTS_DIR, exist_ok=True)
os.makedirs('/home/zulip/logs', exist_ok=True) os.makedirs('/home/zulip/logs', exist_ok=True)
error_rerun_script = "%s/current/scripts/upgrade-zulip-from-git %s" % (DEPLOYMENTS_DIR, refname) error_rerun_script = f"{DEPLOYMENTS_DIR}/current/scripts/upgrade-zulip-from-git {refname}"
get_deployment_lock(error_rerun_script) get_deployment_lock(error_rerun_script)
try: try:

View File

@ -81,7 +81,5 @@ for queue_name in consumers.keys():
else: else:
status = 0 status = 0
with open(state_file_tmp, "w") as f: with open(state_file_tmp, "w") as f:
f.write("%s|%s|%s|queue %s has %s consumers, needs %s\n" % ( f.write(f"{now}|{status}|{states[status]}|queue {queue_name} has {consumers[queue_name]} consumers, needs {target_count}\n")
now, status, states[status], queue_name,
consumers[queue_name], target_count))
os.rename(state_file_tmp, state_file_path) os.rename(state_file_tmp, state_file_path)

View File

@ -32,4 +32,4 @@ def nagios_from_file(results_file: str) -> Tuple[int, str]:
state = pieces[2] state = pieces[2]
data = pieces[3] data = pieces[3]
return (ret, "%s: %s" % (state, data)) return (ret, f"{state}: {data}")

View File

@ -66,7 +66,7 @@ if tornado_processes > 1:
# supervisord group where if any individual process is slow to # supervisord group where if any individual process is slow to
# stop, the whole bundle stays stopped for an extended time. # stop, the whole bundle stays stopped for an extended time.
logging.info("Restarting Tornado process on port %s", p) logging.info("Restarting Tornado process on port %s", p)
subprocess.check_call(["supervisorctl", "restart", "zulip-tornado:port-%s" % (p,)]) subprocess.check_call(["supervisorctl", "restart", f"zulip-tornado:port-{p}"])
else: else:
logging.info("Restarting Tornado process") logging.info("Restarting Tornado process")
subprocess.check_call(["supervisorctl", "restart", "zulip-tornado", "zulip-tornado:*"]) subprocess.check_call(["supervisorctl", "restart", "zulip-tornado", "zulip-tornado:*"])

View File

@ -82,7 +82,7 @@ def generate_secrets(development: bool = False) -> None:
return name not in current_conf return name not in current_conf
def add_secret(name: str, value: str) -> None: def add_secret(name: str, value: str) -> None:
lines.append("%s = %s\n" % (name, value)) lines.append(f"{name} = {value}\n")
current_conf[name] = value current_conf[name] = value
for name in AUTOGENERATED_SETTINGS: for name in AUTOGENERATED_SETTINGS:
@ -178,7 +178,7 @@ def generate_secrets(development: bool = False) -> None:
# the end of the file due to human editing. # the end of the file due to human editing.
f.write("\n" + "".join(lines)) f.write("\n" + "".join(lines))
print("Generated new secrets in %s." % (OUTPUT_SETTINGS_FILENAME,)) print(f"Generated new secrets in {OUTPUT_SETTINGS_FILENAME}.")
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -78,7 +78,7 @@ def strip_unnecesary_tags(text: str) -> str:
text = text[start:end] text = text[start:end]
return text return text
else: else:
raise ValueError("Template does not have %s or %s" % (start_block, end_block)) raise ValueError(f"Template does not have {start_block} or {end_block}")
def get_all_templates_from_directory(directory: str) -> Set[str]: def get_all_templates_from_directory(directory: str) -> Set[str]:
result = set() result = set()

View File

@ -31,7 +31,7 @@ Exec { path => "/usr/sbin:/usr/bin:/sbin:/bin" }
""" """
for pclass in re.split(r'\s*,\s*', config.get('machine', 'puppet_classes')): for pclass in re.split(r'\s*,\s*', config.get('machine', 'puppet_classes')):
puppet_config += "include %s\n" % (pclass,) puppet_config += f"include {pclass}\n"
# We use the puppet configuration from the same Zulip checkout as this script # We use the puppet configuration from the same Zulip checkout as this script
scripts_path = os.path.join(BASE_DIR, "scripts") scripts_path = os.path.join(BASE_DIR, "scripts")

View File

@ -7,7 +7,7 @@ import subprocess
# Open the SVG and find the number text elements using XPath # Open the SVG and find the number text elements using XPath
tree = ET.parse('orig.svg') tree = ET.parse('orig.svg')
elems = [tree.getroot().findall( elems = [tree.getroot().findall(
".//*[@id='%s']/{http://www.w3.org/2000/svg}tspan" % (name,))[0] f".//*[@id='{name}']/{{http://www.w3.org/2000/svg}}tspan")[0]
for name in ('number_back', 'number_front')] for name in ('number_back', 'number_front')]
for i in range(1, 100): for i in range(1, 100):

View File

@ -64,7 +64,7 @@ def check_issue_labels() -> None:
if args.force: if args.force:
response = requests.get(next_page_url) response = requests.get(next_page_url)
else: else:
response = requests.get(next_page_url, headers={'Authorization': 'token %s' % (token,)}) response = requests.get(next_page_url, headers={'Authorization': f'token {token}'})
if response.status_code == 401: if response.status_code == 401:
sys.exit("Error. Please check the token.") sys.exit("Error. Please check the token.")
if response.status_code == 403: if response.status_code == 403:

View File

@ -65,11 +65,11 @@ def create_single_page(pattern: str, out_dir: str, href: str, calls: List[Call])
} }
</style> </style>
''') ''')
f.write('<h3>%s</h3>\n' % (html.escape(pattern),)) f.write(f'<h3>{html.escape(pattern)}</h3>\n')
calls.sort(key=lambda call: call['status_code']) calls.sort(key=lambda call: call['status_code'])
for call in calls: for call in calls:
f.write('<hr>') f.write('<hr>')
f.write('\n%s' % (fix_test_name(call['test_name']),)) f.write('\n{}'.format(fix_test_name(call['test_name'])))
f.write('<div class="test">') f.write('<div class="test">')
try: try:
f.write(call['url']) f.write(call['url'])
@ -77,7 +77,7 @@ def create_single_page(pattern: str, out_dir: str, href: str, calls: List[Call])
f.write(call['url'].encode('utf8')) f.write(call['url'].encode('utf8'))
f.write('<br>\n') f.write('<br>\n')
f.write(call['method'] + '<br>\n') f.write(call['method'] + '<br>\n')
f.write('status code: %s<br>\n' % (call['status_code'],)) f.write('status code: {}<br>\n'.format(call['status_code']))
f.write('<br>') f.write('<br>')
f.write('</div>') f.write('</div>')
@ -136,13 +136,13 @@ def create_user_docs() -> None:
f.write('<ul>\n') f.write('<ul>\n')
for pattern in sorted(groups[name]): for pattern in sorted(groups[name]):
href = pattern.replace('/', '-') + '.html' href = pattern.replace('/', '-') + '.html'
link = '<a href="%s">%s</a>' % (href, html.escape(pattern)) link = f'<a href="{href}">{html.escape(pattern)}</a>'
f.write('<li>' + link + '</li>\n') f.write('<li>' + link + '</li>\n')
create_single_page(pattern, out_dir, href, pattern_dict[pattern]) create_single_page(pattern, out_dir, href, pattern_dict[pattern])
f.write('</ul>') f.write('</ul>')
f.write('\n') f.write('\n')
print('open %s' % (main_page,)) print(f'open {main_page}')
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -190,8 +190,8 @@ def build_id_dict(templates: List[str]) -> (Dict[str, List[str]]):
list_tags = tokenize(text) list_tags = tokenize(text)
except FormattedException as e: except FormattedException as e:
raise Exception(''' raise Exception('''
fn: %s fn: {}
%s''' % (fn, e)) {}'''.format(fn, e))
for tag in list_tags: for tag in list_tags:
info = get_tag_info(tag) info = get_tag_info(tag)

View File

@ -276,7 +276,7 @@ def main(options: argparse.Namespace) -> int:
destroyed = destroy_leaked_test_databases() destroyed = destroy_leaked_test_databases()
if destroyed: if destroyed:
print("Dropped %s stale test databases!" % (destroyed,)) print(f"Dropped {destroyed} stale test databases!")
clean_unused_caches() clean_unused_caches()
@ -304,7 +304,7 @@ def main(options: argparse.Namespace) -> int:
pass pass
version_file = os.path.join(UUID_VAR_PATH, 'provision_version') version_file = os.path.join(UUID_VAR_PATH, 'provision_version')
print('writing to %s\n' % (version_file,)) print(f'writing to {version_file}\n')
open(version_file, 'w').write(PROVISION_VERSION + '\n') open(version_file, 'w').write(PROVISION_VERSION + '\n')
print() print()

View File

@ -11,7 +11,7 @@ def check_venv(filename: str) -> None:
ujson ujson
zulip zulip
except ImportError: except ImportError:
print("You need to run %s inside a Zulip dev environment." % (filename,)) print(f"You need to run {filename} inside a Zulip dev environment.")
user_id = os.getuid() user_id = os.getuid()
user_name = pwd.getpwuid(user_id).pw_name user_name = pwd.getpwuid(user_id).pw_name
if user_name != 'vagrant' and user_name != 'zulipdev': if user_name != 'vagrant' and user_name != 'zulipdev':

View File

@ -213,8 +213,8 @@ def validate(fn: Optional[str] = None, text: Optional[str] = None, check_indent:
tokens = tokenize(text) tokens = tokenize(text)
except FormattedException as e: except FormattedException as e:
raise TemplateParserException(''' raise TemplateParserException('''
fn: %s fn: {}
%s''' % (fn, e)) {}'''.format(fn, e))
class State: class State:
def __init__(self, func: Callable[[Token], None]) -> None: def __init__(self, func: Callable[[Token], None]) -> None:

View File

@ -37,7 +37,7 @@ def assert_server_running(server: "subprocess.Popen[bytes]", log_file: Optional[
if server.poll() is not None: if server.poll() is not None:
message = 'Server died unexpectedly!' message = 'Server died unexpectedly!'
if log_file: if log_file:
message += '\nSee %s\n' % (log_file,) message += f'\nSee {log_file}\n'
raise RuntimeError(message) raise RuntimeError(message)
def server_is_up(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> bool: def server_is_up(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> bool:

View File

@ -5,7 +5,7 @@ import sys
def clean_html(filenames: List[str]) -> None: def clean_html(filenames: List[str]) -> None:
for fn in filenames: for fn in filenames:
print('Prettifying: %s' % (fn,)) print(f'Prettifying: {fn}')
with open(fn) as f: with open(fn) as f:
html = f.read() html = f.read()
phtml = pretty_print_html(html) phtml = pretty_print_html(html)

View File

@ -31,14 +31,14 @@ def check_git_pristine() -> None:
def ensure_on_clean_master() -> None: def ensure_on_clean_master() -> None:
branch = get_git_branch() branch = get_git_branch()
if branch != 'master': if branch != 'master':
exit('You are still on a feature branch: %s' % (branch,)) exit(f'You are still on a feature branch: {branch}')
check_git_pristine() check_git_pristine()
run(['git', 'fetch', 'upstream', 'master']) run(['git', 'fetch', 'upstream', 'master'])
run(['git', 'rebase', 'upstream/master']) run(['git', 'rebase', 'upstream/master'])
def create_pull_branch(pull_id: int) -> None: def create_pull_branch(pull_id: int) -> None:
run(['git', 'fetch', 'upstream', 'pull/%d/head' % (pull_id,)]) run(['git', 'fetch', 'upstream', 'pull/%d/head' % (pull_id,)])
run(['git', 'checkout', '-B', 'review-%s' % (pull_id,), 'FETCH_HEAD']) run(['git', 'checkout', '-B', f'review-{pull_id}', 'FETCH_HEAD'])
run(['git', 'rebase', 'upstream/master']) run(['git', 'rebase', 'upstream/master'])
run(['git', 'log', 'upstream/master..', '--oneline']) run(['git', 'log', 'upstream/master..', '--oneline'])
run(['git', 'diff', 'upstream/master..', '--name-status']) run(['git', 'diff', 'upstream/master..', '--name-status'])

View File

@ -98,7 +98,7 @@ if options.test:
else: else:
settings_module = "zproject.settings" settings_module = "zproject.settings"
manage_args = ['--settings=%s' % (settings_module,)] manage_args = [f'--settings={settings_module}']
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
@ -158,7 +158,7 @@ def server_processes() -> List[List[str]]:
'./puppet/zulip/files/postgresql/process_fts_updates', '--quiet'], './puppet/zulip/files/postgresql/process_fts_updates', '--quiet'],
['./manage.py', 'deliver_scheduled_messages'], ['./manage.py', 'deliver_scheduled_messages'],
['/srv/zulip-thumbor-venv/bin/thumbor', '-c', './zthumbor/thumbor.conf', ['/srv/zulip-thumbor-venv/bin/thumbor', '-c', './zthumbor/thumbor.conf',
'-p', '%s' % (thumbor_port,)], '-p', f'{thumbor_port}'],
] ]
# NORMAL (but slower) operation: # NORMAL (but slower) operation:

View File

@ -79,7 +79,7 @@ def main() -> None:
# anyway, because EMOJI_CACHE_PATH is created by puppet before # anyway, because EMOJI_CACHE_PATH is created by puppet before
# build_emoji would be run. # build_emoji would be run.
run_as_root(["mkdir", "-p", EMOJI_CACHE_PATH]) run_as_root(["mkdir", "-p", EMOJI_CACHE_PATH])
run_as_root(["chown", "%s:%s" % (os.getuid(), os.getgid()), EMOJI_CACHE_PATH]) run_as_root(["chown", f"{os.getuid()}:{os.getgid()}", EMOJI_CACHE_PATH])
sha1_hexdigest = generate_sha1sum_emoji(ZULIP_PATH) sha1_hexdigest = generate_sha1sum_emoji(ZULIP_PATH)
source_emoji_dump = os.path.join(EMOJI_CACHE_PATH, sha1_hexdigest, 'emoji') source_emoji_dump = os.path.join(EMOJI_CACHE_PATH, sha1_hexdigest, 'emoji')
@ -107,7 +107,7 @@ def main() -> None:
os.remove(os.path.join(TARGET_EMOJI_STYLES, filename)) os.remove(os.path.join(TARGET_EMOJI_STYLES, filename))
def percent(f: float) -> str: def percent(f: float) -> str:
return '%0.3f%%' % (f * 100,) return f'{f * 100:0.3f}%'
def get_square_size(emoji_data: List[Dict[str, Any]]) -> int: def get_square_size(emoji_data: List[Dict[str, Any]]) -> int:
""" """
@ -207,7 +207,7 @@ def generate_sprite_css_files(cache_path: str,
'pos_y': percent(emoji["sheet_y"] / (n - 1)), 'pos_y': percent(emoji["sheet_y"] / (n - 1)),
} }
SPRITE_CSS_PATH = os.path.join(cache_path, '%s-sprite.css' % (emojiset,)) SPRITE_CSS_PATH = os.path.join(cache_path, f'{emojiset}-sprite.css')
with open(SPRITE_CSS_PATH, 'w') as f: with open(SPRITE_CSS_PATH, 'w') as f:
f.write(SPRITE_CSS_FILE_TEMPLATE % {'emojiset': emojiset, f.write(SPRITE_CSS_FILE_TEMPLATE % {'emojiset': emojiset,
'alt_name': alt_name, 'alt_name': alt_name,

View File

@ -47,12 +47,12 @@ def load_data(data_file: str) -> List[List[str]]:
def check_uniqueness(emoji_name: str) -> None: def check_uniqueness(emoji_name: str) -> None:
if emoji_name in emoji_names: if emoji_name in emoji_names:
raise Exception("Duplicate emoji name: %s" % (emoji_name,)) raise Exception(f"Duplicate emoji name: {emoji_name}")
emoji_names.add(emoji_name) emoji_names.add(emoji_name)
def check_valid_emoji_name(emoji_name: str) -> None: def check_valid_emoji_name(emoji_name: str) -> None:
if re.fullmatch("[+-]?[a-z0-9_-]+", emoji_name) is None: if re.fullmatch("[+-]?[a-z0-9_-]+", emoji_name) is None:
raise Exception("Invalid emoji name: %s" % (emoji_name,)) raise Exception(f"Invalid emoji name: {emoji_name}")
def check_emoji_names(canonical_name: str, aliases: List[str]) -> None: def check_emoji_names(canonical_name: str, aliases: List[str]) -> None:
if canonical_name == 'X': if canonical_name == 'X':

View File

@ -314,7 +314,7 @@ def main() -> None:
classname = suite.rsplit('.', 1)[0] classname = suite.rsplit('.', 1)[0]
rewrite_arguments(classname) rewrite_arguments(classname)
elif suite[0].isupper(): elif suite[0].isupper():
rewrite_arguments('class %s(' % (suite,)) rewrite_arguments(f'class {suite}(')
for i, suite in enumerate(args): for i, suite in enumerate(args):
if suite.startswith('test'): if suite.startswith('test'):
@ -403,7 +403,7 @@ def main() -> None:
# We only check the templates if all the tests ran and passed # We only check the templates if all the tests ran and passed
if not failures and full_suite and templates_not_rendered: if not failures and full_suite and templates_not_rendered:
missed_count = len(templates_not_rendered) missed_count = len(templates_not_rendered)
print("\nError: %s templates have no tests!" % (missed_count,)) print(f"\nError: {missed_count} templates have no tests!")
for template in templates_not_rendered: for template in templates_not_rendered:
print(f' {template}') print(f' {template}')
print("See zerver/tests/test_templates.py for the exclude list.") print("See zerver/tests/test_templates.py for the exclude list.")
@ -424,8 +424,8 @@ def main() -> None:
for path in enforce_fully_covered: for path in enforce_fully_covered:
missing_lines = cov.analysis2(path)[3] missing_lines = cov.analysis2(path)[3]
if len(missing_lines) > 0: if len(missing_lines) > 0:
print("ERROR: %s no longer has complete backend test coverage" % (path,)) print(f"ERROR: {path} no longer has complete backend test coverage")
print(" Lines missing coverage: %s" % (missing_lines,)) print(f" Lines missing coverage: {missing_lines}")
print() print()
failures = True failures = True
if failures: if failures:
@ -439,7 +439,7 @@ def main() -> None:
try: try:
missing_lines = cov.analysis2(path)[3] missing_lines = cov.analysis2(path)[3]
if len(missing_lines) == 0 and path != "zerver/lib/migrate.py": if len(missing_lines) == 0 and path != "zerver/lib/migrate.py":
print("ERROR: %s has complete backend test coverage but is still in not_yet_fully_covered." % (path,)) print(f"ERROR: {path} has complete backend test coverage but is still in not_yet_fully_covered.")
ok = False ok = False
except coverage.misc.NoSource: except coverage.misc.NoSource:
continue continue
@ -471,7 +471,7 @@ def main() -> None:
removed = remove_test_run_directories() removed = remove_test_run_directories()
if removed: if removed:
print("Removed %s stale test run directories!" % (removed,)) print(f"Removed {removed} stale test run directories!")
# We'll have printed whether tests passed or failed above # We'll have printed whether tests passed or failed above
sys.exit(bool(failures)) sys.exit(bool(failures))

View File

@ -242,7 +242,7 @@ def run_tests_via_node_js() -> int:
try: try:
ret = subprocess.check_call(command) ret = subprocess.check_call(command)
except OSError: except OSError:
print('Bad command: %s' % (command,)) print(f'Bad command: {command}')
raise raise
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print('\n** Tests failed, PLEASE FIX! **\n') print('\n** Tests failed, PLEASE FIX! **\n')
@ -257,8 +257,8 @@ def check_line_coverage(fn: str, line_coverage: Dict[Any, Any], line_mapping: Di
missing_lines.append(str(actual_line["start"]["line"])) missing_lines.append(str(actual_line["start"]["line"]))
if missing_lines: if missing_lines:
if log: if log:
print_error("%s no longer has complete node test coverage" % (fn,)) print_error(f"{fn} no longer has complete node test coverage")
print(" Lines missing coverage: %s" % (", ".join(sorted(missing_lines, key=int)),)) print(" Lines missing coverage: {}".format(", ".join(sorted(missing_lines, key=int))))
print() print()
return False return False
return True return True
@ -288,7 +288,7 @@ def enforce_proper_coverage(coverage_json: Any) -> bool:
path = ROOT_DIR + "/" + relative_path path = ROOT_DIR + "/" + relative_path
if not (path in coverage_json): if not (path in coverage_json):
coverage_lost = True coverage_lost = True
print_error("%s has no node test coverage" % (relative_path,)) print_error(f"{relative_path} has no node test coverage")
continue continue
line_coverage = coverage_json[path]['s'] line_coverage = coverage_json[path]['s']
line_mapping = coverage_json[path]['statementMap'] line_mapping = coverage_json[path]['statementMap']

View File

@ -58,7 +58,7 @@ def run_tests(files: Iterable[str], external_host: str) -> None:
for test_file in test_files: for test_file in test_files:
test_name = os.path.basename(test_file) test_name = os.path.basename(test_file)
cmd = ["node"] + [test_file] cmd = ["node"] + [test_file]
print("\n\n===================== %s\nRunning %s\n\n" % (test_name, " ".join(map(shlex.quote, cmd))), flush=True) print("\n\n===================== {}\nRunning {}\n\n".format(test_name, " ".join(map(shlex.quote, cmd))), flush=True)
ret = subprocess.call(cmd) ret = subprocess.call(cmd)
if ret != 0: if ret != 0:
return ret return ret

View File

@ -108,14 +108,14 @@ class TestHtmlBranches(unittest.TestCase):
self.assertEqual(set(template_id_dict.keys()), {'below_navbar', 'hello_{{ message }}', 'intro'}) self.assertEqual(set(template_id_dict.keys()), {'below_navbar', 'hello_{{ message }}', 'intro'})
self.assertEqual(template_id_dict['hello_{{ message }}'], [ self.assertEqual(template_id_dict['hello_{{ message }}'], [
'Line 12:%s/tools/tests/test_template_data/test_template1.html' % (ZULIP_PATH,), f'Line 12:{ZULIP_PATH}/tools/tests/test_template_data/test_template1.html',
'Line 12:%s/tools/tests/test_template_data/test_template2.html' % (ZULIP_PATH,)]) f'Line 12:{ZULIP_PATH}/tools/tests/test_template_data/test_template2.html'])
self.assertEqual(template_id_dict['intro'], [ self.assertEqual(template_id_dict['intro'], [
'Line 10:%s/tools/tests/test_template_data/test_template1.html' % (ZULIP_PATH,), f'Line 10:{ZULIP_PATH}/tools/tests/test_template_data/test_template1.html',
'Line 11:%s/tools/tests/test_template_data/test_template1.html' % (ZULIP_PATH,), f'Line 11:{ZULIP_PATH}/tools/tests/test_template_data/test_template1.html',
'Line 11:%s/tools/tests/test_template_data/test_template2.html' % (ZULIP_PATH,)]) f'Line 11:{ZULIP_PATH}/tools/tests/test_template_data/test_template2.html'])
self.assertEqual(template_id_dict['below_navbar'], [ self.assertEqual(template_id_dict['below_navbar'], [
'Line 10:%s/tools/tests/test_template_data/test_template2.html' % (ZULIP_PATH,)]) f'Line 10:{ZULIP_PATH}/tools/tests/test_template_data/test_template2.html'])
def test_split_for_id_and_class(self) -> None: def test_split_for_id_and_class(self) -> None:
id1 = "{{ red|blue }}" id1 = "{{ red|blue }}"

View File

@ -65,11 +65,11 @@ for zuliprc_path in zuliprc_paths_list:
with open(zuliprc_path, 'w+') as w: with open(zuliprc_path, 'w+') as w:
zuliprc.write(w) zuliprc.write(w)
result = 'SUCCESS' result = 'SUCCESS'
reason = 'API field updated for user %s' % (email,) reason = f'API field updated for user {email}'
except OSError: except OSError:
result = 'FAILURE' result = 'FAILURE'
reason = 'Writing to file unsuccessful' reason = 'Writing to file unsuccessful'
else: else:
result = 'SUCCESS' result = 'SUCCESS'
reason = 'API key for user %s is already consistent' % (email,) reason = f'API key for user {email} is already consistent'
print(f'{zuliprc_path}: {result}: {reason}') print(f'{zuliprc_path}: {result}: {reason}')

View File

@ -97,9 +97,9 @@ def build_for_most_tests() -> None:
with open('tools/webpack.assets.json') as json_data: with open('tools/webpack.assets.json') as json_data:
for entry in json.load(json_data).keys(): for entry in json.load(json_data).keys():
entries[entry] = [{ entries[entry] = [{
"name": "%s.js" % (entry,), "name": f"{entry}.js",
"publicPath": "http://localhost:3000/webpack-stub/%s-stubentry.js" % (entry,), "publicPath": f"http://localhost:3000/webpack-stub/{entry}-stubentry.js",
"path": "/stubfolder/%s-stubfile.js" % (entry,) "path": f"/stubfolder/{entry}-stubfile.js"
}] }]
stat_data = { stat_data = {
"status": "done", "status": "done",

View File

@ -81,7 +81,7 @@ for msg in result['messages']:
msg.pop(k, None) msg.pop(k, None)
messages.append(msg) messages.append(msg)
filename = "zulip-%s.json" % (options.stream,) filename = f"zulip-{options.stream}.json"
with open(filename, 'wb') as f: with open(filename, 'wb') as f:
f.write(json.dumps(messages, indent=0, sort_keys=False).encode('utf-8')) f.write(json.dumps(messages, indent=0, sort_keys=False).encode('utf-8'))
print("%d messages exported to %s" % (len(messages), filename,)) print("%d messages exported to %s" % (len(messages), filename,))

View File

@ -141,7 +141,7 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
'landing_page_navbar_message': settings.LANDING_PAGE_NAVBAR_MESSAGE, 'landing_page_navbar_message': settings.LANDING_PAGE_NAVBAR_MESSAGE,
} }
context['OPEN_GRAPH_URL'] = '%s%s' % (realm_uri, request.path) context['OPEN_GRAPH_URL'] = f'{realm_uri}{request.path}'
if realm is not None and realm.icon_source == realm.ICON_UPLOADED: if realm is not None and realm.icon_source == realm.ICON_UPLOADED:
context['OPEN_GRAPH_IMAGE'] = urljoin(realm_uri, realm_icon) context['OPEN_GRAPH_IMAGE'] = urljoin(realm_uri, realm_icon)
@ -175,7 +175,7 @@ def login_context(request: HttpRequest) -> Dict[str, Any]:
no_auth_enabled = True no_auth_enabled = True
for auth_backend_name in AUTH_BACKEND_NAME_MAP: for auth_backend_name in AUTH_BACKEND_NAME_MAP:
name_lower = auth_backend_name.lower() name_lower = auth_backend_name.lower()
key = "%s_auth_enabled" % (name_lower,) key = f"{name_lower}_auth_enabled"
is_enabled = auth_enabled_helper([auth_backend_name], realm) is_enabled = auth_enabled_helper([auth_backend_name], realm)
context[key] = is_enabled context[key] = is_enabled
if is_enabled: if is_enabled:
@ -191,7 +191,7 @@ def login_context(request: HttpRequest) -> Dict[str, Any]:
external_authentication_methods = get_external_method_dicts(realm) external_authentication_methods = get_external_method_dicts(realm)
) )
for auth_dict in context['page_params']['external_authentication_methods']: for auth_dict in context['page_params']['external_authentication_methods']:
auth_dict['button_id_suffix'] = "auth_button_%s" % (auth_dict['name'],) auth_dict['button_id_suffix'] = "auth_button_{}".format(auth_dict['name'])
return context return context

View File

@ -97,7 +97,7 @@ def build_userprofile(timestamp: Any, domain_name: str,
def get_user_email(user_data: ZerverFieldsT, domain_name: str) -> str: def get_user_email(user_data: ZerverFieldsT, domain_name: str) -> str:
# TODO Get user email from github # TODO Get user email from github
email = ("%s@users.noreply.github.com" % (user_data['username'],)) email = ("{}@users.noreply.github.com".format(user_data['username']))
return email return email
def build_stream_map(timestamp: Any, def build_stream_map(timestamp: Any,
@ -240,14 +240,14 @@ def get_usermentions(message: Dict[str, Any], user_map: Dict[str, int],
if 'mentions' in message: if 'mentions' in message:
for mention in message['mentions']: for mention in message['mentions']:
if mention.get('userId') in user_map: if mention.get('userId') in user_map:
gitter_mention = '@%s' % (mention['screenName'],) gitter_mention = '@{}'.format(mention['screenName'])
if mention['screenName'] not in user_short_name_to_full_name: if mention['screenName'] not in user_short_name_to_full_name:
logging.info("Mentioned user %s never sent any messages, so has no full name data", logging.info("Mentioned user %s never sent any messages, so has no full name data",
mention['screenName']) mention['screenName'])
full_name = mention['screenName'] full_name = mention['screenName']
else: else:
full_name = user_short_name_to_full_name[mention['screenName']] full_name = user_short_name_to_full_name[mention['screenName']]
zulip_mention = ('@**%s**' % (full_name,)) zulip_mention = (f'@**{full_name}**')
message['text'] = message['text'].replace(gitter_mention, zulip_mention) message['text'] = message['text'].replace(gitter_mention, zulip_mention)
mentioned_user_ids.append(user_map[mention['userId']]) mentioned_user_ids.append(user_map[mention['userId']])

View File

@ -50,7 +50,7 @@ def build_zerver_realm(realm_id: int, realm_subdomain: str, time: float,
other_product: str) -> List[ZerverFieldsT]: other_product: str) -> List[ZerverFieldsT]:
realm = Realm(id=realm_id, date_created=time, realm = Realm(id=realm_id, date_created=time,
name=realm_subdomain, string_id=realm_subdomain, name=realm_subdomain, string_id=realm_subdomain,
description="Organization imported from %s!" % (other_product,)) description=f"Organization imported from {other_product}!")
auth_methods = [[flag[0], flag[1]] for flag in realm.authentication_methods] auth_methods = [[flag[0], flag[1]] for flag in realm.authentication_methods]
realm_dict = model_to_dict(realm, exclude='authentication_methods') realm_dict = model_to_dict(realm, exclude='authentication_methods')
realm_dict['authentication_methods'] = auth_methods realm_dict['authentication_methods'] = auth_methods
@ -514,8 +514,8 @@ def process_avatars(avatar_list: List[ZerverFieldsT], avatar_dir: str, realm_id:
avatar_url = avatar['path'] avatar_url = avatar['path']
avatar_original = dict(avatar) avatar_original = dict(avatar)
image_path = '%s.png' % (avatar_hash,) image_path = f'{avatar_hash}.png'
original_image_path = '%s.original' % (avatar_hash,) original_image_path = f'{avatar_hash}.original'
avatar_upload_list.append([avatar_url, image_path, original_image_path]) avatar_upload_list.append([avatar_url, image_path, original_image_path])
# We don't add the size field here in avatar's records.json, # We don't add the size field here in avatar's records.json,

View File

@ -227,7 +227,7 @@ def build_customprofile_field(customprofile_field: List[ZerverFieldsT], fields:
if field in slack_custom_fields: if field in slack_custom_fields:
field_name = field field_name = field
else: else:
field_name = "slack custom field %s" % (str(custom_profile_field_id + 1),) field_name = f"slack custom field {str(custom_profile_field_id + 1)}"
customprofilefield = CustomProfileField( customprofilefield = CustomProfileField(
id=custom_profile_field_id, id=custom_profile_field_id,
name=field_name, name=field_name,
@ -294,10 +294,10 @@ def get_user_email(user: ZerverFieldsT, domain_name: str) -> str:
slack_bot_name = user['profile']['first_name'] slack_bot_name = user['profile']['first_name']
else: else:
raise AssertionError("Could not identify bot type") raise AssertionError("Could not identify bot type")
return slack_bot_name.replace("Bot", "").replace(" ", "") + "-bot@%s" % (domain_name,) return slack_bot_name.replace("Bot", "").replace(" ", "") + f"-bot@{domain_name}"
if get_user_full_name(user).lower() == "slackbot": if get_user_full_name(user).lower() == "slackbot":
return "imported-slackbot-bot@%s" % (domain_name,) return f"imported-slackbot-bot@{domain_name}"
raise AssertionError("Could not find email address for Slack user %s" % (user,)) raise AssertionError(f"Could not find email address for Slack user {user}")
def build_avatar_url(slack_user_id: str, team_id: str, avatar_hash: str) -> str: def build_avatar_url(slack_user_id: str, team_id: str, avatar_hash: str) -> str:
avatar_url = f"https://ca.slack-edge.com/{team_id}-{slack_user_id}-{avatar_hash}" avatar_url = f"https://ca.slack-edge.com/{team_id}-{slack_user_id}-{avatar_hash}"
@ -742,7 +742,7 @@ def channel_message_to_zerver_message(realm_id: int,
# For example "sh_room_created" has the message 'started a call' # For example "sh_room_created" has the message 'started a call'
# which should be displayed as '/me started a call' # which should be displayed as '/me started a call'
if subtype in ["bot_add", "sh_room_created", "me_message"]: if subtype in ["bot_add", "sh_room_created", "me_message"]:
content = '/me %s' % (content,) content = f'/me {content}'
if subtype == 'file_comment': if subtype == 'file_comment':
# The file_comment message type only indicates the # The file_comment message type only indicates the
# responsible user in a subfield. # responsible user in a subfield.
@ -864,7 +864,7 @@ def process_message_files(message: ZerverFieldsT,
file_name = fileinfo['title'] file_name = fileinfo['title']
else: else:
file_name = fileinfo['name'] file_name = fileinfo['name']
markdown_links.append('[%s](%s)' % (file_name, fileinfo['url_private'])) markdown_links.append('[{}]({})'.format(file_name, fileinfo['url_private']))
content = '\n'.join(markdown_links) content = '\n'.join(markdown_links)
@ -887,8 +887,8 @@ def get_attachment_path_and_content(fileinfo: ZerverFieldsT, realm_id: int) -> T
random_name(18), random_name(18),
sanitize_name(fileinfo['name']) sanitize_name(fileinfo['name'])
]) ])
attachment_path = '/user_uploads/%s' % (s3_path,) attachment_path = f'/user_uploads/{s3_path}'
content = '[%s](%s)' % (fileinfo['title'], attachment_path) content = '[{}]({})'.format(fileinfo['title'], attachment_path)
return s3_path, content return s3_path, content
@ -1119,7 +1119,7 @@ def get_slack_api_data(slack_api_url: str, get_param: str, **kwargs: Any) -> Any
if data.status_code == requests.codes.ok: if data.status_code == requests.codes.ok:
result = data.json() result = data.json()
if not result['ok']: if not result['ok']:
raise Exception('Error accessing Slack API: %s' % (result['error'],)) raise Exception('Error accessing Slack API: {}'.format(result['error']))
return result[get_param] return result[get_param]
raise Exception('HTTP error accessing the Slack API.') raise Exception('HTTP error accessing the Slack API.')

View File

@ -85,7 +85,7 @@ def convert_to_zulip_markdown(text: str, users: List[ZerverFieldsT],
# Map Slack channel mention: '<#C5Z73A7RA|general>' to '#**general**' # Map Slack channel mention: '<#C5Z73A7RA|general>' to '#**general**'
for cname, ids in added_channels.items(): for cname, ids in added_channels.items():
cid = ids[0] cid = ids[0]
text = text.replace('<#%s|%s>' % (cid, cname), '#**' + cname + '**') text = text.replace(f'<#{cid}|{cname}>', '#**' + cname + '**')
tokens = text.split(' ') tokens = text.split(' ')
for iterator in range(len(tokens)): for iterator in range(len(tokens)):

View File

@ -57,7 +57,7 @@ def email_is_not_mit_mailing_list(email: str) -> None:
username = email.rsplit("@", 1)[0] username = email.rsplit("@", 1)[0]
# Check whether the user exists and can get mail. # Check whether the user exists and can get mail.
try: try:
DNS.dnslookup("%s.pobox.ns.athena.mit.edu" % (username,), DNS.Type.TXT) DNS.dnslookup(f"{username}.pobox.ns.athena.mit.edu", DNS.Type.TXT)
except DNS.Base.ServerError as e: except DNS.Base.ServerError as e:
if e.rcode == DNS.Status.NXDOMAIN: if e.rcode == DNS.Status.NXDOMAIN:
raise ValidationError(mark_safe(MIT_VALIDATION_ERROR)) raise ValidationError(mark_safe(MIT_VALIDATION_ERROR))

View File

@ -394,10 +394,7 @@ def process_new_human_user(user_profile: UserProfile,
user_profile.realm, user_profile.realm,
get_system_bot(settings.NOTIFICATION_BOT), get_system_bot(settings.NOTIFICATION_BOT),
prereg_user.referred_by, prereg_user.referred_by,
"%s <`%s`> accepted your invitation to join Zulip!" % ( f"{user_profile.full_name} <`{user_profile.email}`> accepted your invitation to join Zulip!"
user_profile.full_name,
user_profile.email,
)
) )
# Mark any other PreregistrationUsers that are STATUS_ACTIVE as # Mark any other PreregistrationUsers that are STATUS_ACTIVE as
# inactive so we can keep track of the PreregistrationUser we # inactive so we can keep track of the PreregistrationUser we
@ -598,8 +595,7 @@ def do_set_realm_property(realm: Realm, name: str, value: Any) -> None:
""" """
property_type = Realm.property_types[name] property_type = Realm.property_types[name]
assert isinstance(value, property_type), ( assert isinstance(value, property_type), (
'Cannot update %s: %s is not an instance of %s' % ( f'Cannot update {name}: {value} is not an instance of {property_type}')
name, value, property_type,))
old_value = getattr(realm, name) old_value = getattr(realm, name)
setattr(realm, name, value) setattr(realm, name, value)
@ -2359,8 +2355,7 @@ def _internal_prep_message(realm: Realm,
return check_message(sender, get_client("Internal"), addressee, return check_message(sender, get_client("Internal"), addressee,
content, realm=realm) content, realm=realm)
except JsonableError as e: except JsonableError as e:
logging.exception("Error queueing internal message by %s: %s" % ( logging.exception(f"Error queueing internal message by {sender.delivery_email}: {e}")
sender.delivery_email, e))
return None return None
@ -3587,7 +3582,7 @@ def do_change_stream_description(stream: Stream, new_description: str) -> None:
def do_create_realm(string_id: str, name: str, def do_create_realm(string_id: str, name: str,
emails_restricted_to_domains: Optional[bool]=None) -> Realm: emails_restricted_to_domains: Optional[bool]=None) -> Realm:
if Realm.objects.filter(string_id=string_id).exists(): if Realm.objects.filter(string_id=string_id).exists():
raise AssertionError("Realm %s already exists!" % (string_id,)) raise AssertionError(f"Realm {string_id} already exists!")
if not server_initialized(): if not server_initialized():
logging.info("Server not yet initialized. Creating the internal realm first.") logging.info("Server not yet initialized. Creating the internal realm first.")
create_internal_realm() create_internal_realm()
@ -3653,8 +3648,7 @@ def do_change_notification_settings(user_profile: UserProfile, name: str,
notification_setting_type = UserProfile.notification_setting_types[name] notification_setting_type = UserProfile.notification_setting_types[name]
assert isinstance(value, notification_setting_type), ( assert isinstance(value, notification_setting_type), (
'Cannot update %s: %s is not an instance of %s' % ( f'Cannot update {name}: {value} is not an instance of {notification_setting_type}')
name, value, notification_setting_type,))
setattr(user_profile, name, value) setattr(user_profile, name, value)
@ -4179,7 +4173,7 @@ def do_update_message_flags(user_profile: UserProfile,
if flag == "read" and operation == "add": if flag == "read" and operation == "add":
do_clear_mobile_push_notifications_for_ids(user_profile, messages) do_clear_mobile_push_notifications_for_ids(user_profile, messages)
statsd.incr("flags.%s.%s" % (flag, operation), count) statsd.incr(f"flags.{flag}.{operation}", count)
return count return count
class MessageUpdateUserInfoResult(TypedDict): class MessageUpdateUserInfoResult(TypedDict):
@ -4199,9 +4193,9 @@ def notify_topic_moved_streams(user_profile: UserProfile,
if new_topic is None: if new_topic is None:
new_topic = old_topic new_topic = old_topic
user_mention = "@_**%s|%s**" % (user_profile.full_name, user_profile.id) user_mention = f"@_**{user_profile.full_name}|{user_profile.id}**"
old_topic_link = "#**%s>%s**" % (old_stream.name, old_topic) old_topic_link = f"#**{old_stream.name}>{old_topic}**"
new_topic_link = "#**%s>%s**" % (new_stream.name, new_topic) new_topic_link = f"#**{new_stream.name}>{new_topic}**"
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,
@ -4918,7 +4912,7 @@ def do_send_confirmation_email(invitee: PreregistrationUser,
activation_url = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION) activation_url = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION)
context = {'referrer_full_name': referrer.full_name, 'referrer_email': referrer.delivery_email, context = {'referrer_full_name': referrer.full_name, 'referrer_email': referrer.delivery_email,
'activate_url': activation_url, 'referrer_realm_name': referrer.realm.name} 'activate_url': activation_url, 'referrer_realm_name': referrer.realm.name}
from_name = "%s (via Zulip)" % (referrer.full_name,) from_name = f"{referrer.full_name} (via Zulip)"
send_email('zerver/emails/invitation', to_emails=[invitee.email], from_name=from_name, send_email('zerver/emails/invitation', to_emails=[invitee.email], from_name=from_name,
from_address=FromAddress.tokenized_no_reply_address(), from_address=FromAddress.tokenized_no_reply_address(),
language=referrer.realm.default_language, context=context) language=referrer.realm.default_language, context=context)

View File

@ -92,9 +92,9 @@ def get_gravatar_url(email: str, avatar_version: int, medium: bool=False) -> str
def _get_unversioned_gravatar_url(email: str, medium: bool) -> str: def _get_unversioned_gravatar_url(email: str, medium: bool) -> str:
if settings.ENABLE_GRAVATAR: if settings.ENABLE_GRAVATAR:
gravitar_query_suffix = "&s=%s" % (MEDIUM_AVATAR_SIZE,) if medium else "" gravitar_query_suffix = f"&s={MEDIUM_AVATAR_SIZE}" if medium else ""
hash_key = gravatar_hash(email) hash_key = gravatar_hash(email)
return "https://secure.gravatar.com/avatar/%s?d=identicon%s" % (hash_key, gravitar_query_suffix) return f"https://secure.gravatar.com/avatar/{hash_key}?d=identicon{gravitar_query_suffix}"
return settings.DEFAULT_AVATAR_URI+'?x=x' return settings.DEFAULT_AVATAR_URI+'?x=x'
def _get_unversioned_avatar_url(user_profile_id: int, def _get_unversioned_avatar_url(user_profile_id: int,

View File

@ -34,7 +34,7 @@ def user_avatar_path(user_profile: UserProfile) -> str:
def user_avatar_path_from_ids(user_profile_id: int, realm_id: int) -> str: def user_avatar_path_from_ids(user_profile_id: int, realm_id: int) -> str:
user_id_hash = user_avatar_hash(str(user_profile_id)) user_id_hash = user_avatar_hash(str(user_profile_id))
return '%s/%s' % (str(realm_id), user_id_hash) return f'{str(realm_id)}/{user_id_hash}'
def user_avatar_content_hash(ldap_avatar: bytes) -> str: def user_avatar_content_hash(ldap_avatar: bytes) -> str:
return hashlib.sha256(ldap_avatar).hexdigest() return hashlib.sha256(ldap_avatar).hexdigest()

View File

@ -27,7 +27,7 @@ def get_bot_handler(service_name: str) -> Any:
configured_service = embedded_bot_service.name configured_service = embedded_bot_service.name
if not configured_service: if not configured_service:
return None return None
bot_module_name = 'zulip_bots.bots.%s.%s' % (configured_service, configured_service) bot_module_name = f'zulip_bots.bots.{configured_service}.{configured_service}'
bot_module: Any = importlib.import_module(bot_module_name) bot_module: Any = importlib.import_module(bot_module_name)
return bot_module.handler_class() return bot_module.handler_class()

View File

@ -34,9 +34,9 @@ gear_instructions = """
def gear_handle_match(key: str) -> str: def gear_handle_match(key: str) -> str:
if relative_help_links: if relative_help_links:
item = '[%s](%s)' % (gear_info[key][0], gear_info[key][1]) item = f'[{gear_info[key][0]}]({gear_info[key][1]})'
else: else:
item = '**%s**' % (gear_info[key][0],) item = f'**{gear_info[key][0]}**'
return gear_instructions % {'item': item} return gear_instructions % {'item': item}
@ -54,7 +54,7 @@ stream_instructions_no_link = """
def stream_handle_match(key: str) -> str: def stream_handle_match(key: str) -> str:
if relative_help_links: if relative_help_links:
return "1. Go to [%s](%s)." % (stream_info[key][0], stream_info[key][1]) return f"1. Go to [{stream_info[key][0]}]({stream_info[key][1]})."
if key == 'all': if key == 'all':
return stream_instructions_no_link + "\n\n1. Click **All streams** in the upper left." return stream_instructions_no_link + "\n\n1. Click **All streams** in the upper left."
return stream_instructions_no_link return stream_instructions_no_link

View File

@ -103,9 +103,9 @@ class Setting(Preprocessor):
setting_name = link_mapping[setting_identifier][1] setting_name = link_mapping[setting_identifier][1]
setting_link = link_mapping[setting_identifier][2] setting_link = link_mapping[setting_identifier][2]
if relative_settings_links: if relative_settings_links:
return "1. Go to [%s](%s)." % (setting_name, setting_link) return f"1. Go to [{setting_name}]({setting_link})."
return settings_markdown % {'setting_type_name': setting_type_name, return settings_markdown % {'setting_type_name': setting_type_name,
'setting_reference': "**%s**" % (setting_name,)} 'setting_reference': f"**{setting_name}**"}
def makeExtension(*args: Any, **kwargs: Any) -> SettingHelpExtension: def makeExtension(*args: Any, **kwargs: Any) -> SettingHelpExtension:
return SettingHelpExtension(*args, **kwargs) return SettingHelpExtension(*args, **kwargs)

View File

@ -176,7 +176,7 @@ def cache_with_key(
metric_key = statsd_key(key) metric_key = statsd_key(key)
status = "hit" if val is not None else "miss" status = "hit" if val is not None else "miss"
statsd.incr("cache%s.%s.%s" % (extra, metric_key, status)) statsd.incr(f"cache{extra}.{metric_key}.{status}")
# Values are singleton tuples so that we can distinguish # Values are singleton tuples so that we can distinguish
# a result of None from a missing key. # a result of None from a missing key.
@ -409,7 +409,7 @@ def generic_bulk_cached_fetch(
if cache_keys[object_id] in cached_objects} if cache_keys[object_id] in cached_objects}
def preview_url_cache_key(url: str) -> str: def preview_url_cache_key(url: str) -> str:
return "preview_url:%s" % (make_safe_digest(url),) return f"preview_url:{make_safe_digest(url)}"
def display_recipient_cache_key(recipient_id: int) -> str: def display_recipient_cache_key(recipient_id: int) -> str:
return "display_recipient_dict:%d" % (recipient_id,) return "display_recipient_dict:%d" % (recipient_id,)
@ -423,22 +423,22 @@ def user_profile_by_email_cache_key(email: str) -> str:
# See the comment in zerver/lib/avatar_hash.py:gravatar_hash for why we # See the comment in zerver/lib/avatar_hash.py:gravatar_hash for why we
# are proactively encoding email addresses even though they will # are proactively encoding email addresses even though they will
# with high likelihood be ASCII-only for the foreseeable future. # with high likelihood be ASCII-only for the foreseeable future.
return 'user_profile_by_email:%s' % (make_safe_digest(email.strip()),) return f'user_profile_by_email:{make_safe_digest(email.strip())}'
def user_profile_cache_key_id(email: str, realm_id: int) -> str: def user_profile_cache_key_id(email: str, realm_id: int) -> str:
return "user_profile:%s:%s" % (make_safe_digest(email.strip()), realm_id,) return f"user_profile:{make_safe_digest(email.strip())}:{realm_id}"
def user_profile_cache_key(email: str, realm: 'Realm') -> str: def user_profile_cache_key(email: str, realm: 'Realm') -> str:
return user_profile_cache_key_id(email, realm.id) return user_profile_cache_key_id(email, realm.id)
def bot_profile_cache_key(email: str) -> str: def bot_profile_cache_key(email: str) -> str:
return "bot_profile:%s" % (make_safe_digest(email.strip()),) return f"bot_profile:{make_safe_digest(email.strip())}"
def user_profile_by_id_cache_key(user_profile_id: int) -> str: def user_profile_by_id_cache_key(user_profile_id: int) -> str:
return "user_profile_by_id:%s" % (user_profile_id,) return f"user_profile_by_id:{user_profile_id}"
def user_profile_by_api_key_cache_key(api_key: str) -> str: def user_profile_by_api_key_cache_key(api_key: str) -> str:
return "user_profile_by_api_key:%s" % (api_key,) return f"user_profile_by_api_key:{api_key}"
realm_user_dict_fields: List[str] = [ realm_user_dict_fields: List[str] = [
'id', 'full_name', 'short_name', 'email', 'id', 'full_name', 'short_name', 'email',
@ -449,16 +449,16 @@ realm_user_dict_fields: List[str] = [
] ]
def realm_user_dicts_cache_key(realm_id: int) -> str: def realm_user_dicts_cache_key(realm_id: int) -> str:
return "realm_user_dicts:%s" % (realm_id,) return f"realm_user_dicts:{realm_id}"
def get_realm_used_upload_space_cache_key(realm: 'Realm') -> str: def get_realm_used_upload_space_cache_key(realm: 'Realm') -> str:
return 'realm_used_upload_space:%s' % (realm.id,) return f'realm_used_upload_space:{realm.id}'
def active_user_ids_cache_key(realm_id: int) -> str: def active_user_ids_cache_key(realm_id: int) -> str:
return "active_user_ids:%s" % (realm_id,) return f"active_user_ids:{realm_id}"
def active_non_guest_user_ids_cache_key(realm_id: int) -> str: def active_non_guest_user_ids_cache_key(realm_id: int) -> str:
return "active_non_guest_user_ids:%s" % (realm_id,) return f"active_non_guest_user_ids:{realm_id}"
bot_dict_fields: List[str] = [ bot_dict_fields: List[str] = [
'api_key', 'api_key',
@ -478,11 +478,10 @@ bot_dict_fields: List[str] = [
] ]
def bot_dicts_in_realm_cache_key(realm: 'Realm') -> str: def bot_dicts_in_realm_cache_key(realm: 'Realm') -> str:
return "bot_dicts_in_realm:%s" % (realm.id,) return f"bot_dicts_in_realm:{realm.id}"
def get_stream_cache_key(stream_name: str, realm_id: int) -> str: def get_stream_cache_key(stream_name: str, realm_id: int) -> str:
return "stream_by_realm_and_name:%s:%s" % ( return f"stream_by_realm_and_name:{realm_id}:{make_safe_digest(stream_name.strip().lower())}"
realm_id, make_safe_digest(stream_name.strip().lower()))
def delete_user_profile_caches(user_profiles: Iterable['UserProfile']) -> None: def delete_user_profile_caches(user_profiles: Iterable['UserProfile']) -> None:
# Imported here to avoid cyclic dependency. # Imported here to avoid cyclic dependency.
@ -571,16 +570,16 @@ def flush_realm(sender: Any, **kwargs: Any) -> None:
cache_delete(realm_text_description_cache_key(realm)) cache_delete(realm_text_description_cache_key(realm))
def realm_alert_words_cache_key(realm: 'Realm') -> str: def realm_alert_words_cache_key(realm: 'Realm') -> str:
return "realm_alert_words:%s" % (realm.string_id,) return f"realm_alert_words:{realm.string_id}"
def realm_alert_words_automaton_cache_key(realm: 'Realm') -> str: def realm_alert_words_automaton_cache_key(realm: 'Realm') -> str:
return "realm_alert_words_automaton:%s" % (realm.string_id,) return f"realm_alert_words_automaton:{realm.string_id}"
def realm_rendered_description_cache_key(realm: 'Realm') -> str: def realm_rendered_description_cache_key(realm: 'Realm') -> str:
return "realm_rendered_description:%s" % (realm.string_id,) return f"realm_rendered_description:{realm.string_id}"
def realm_text_description_cache_key(realm: 'Realm') -> str: def realm_text_description_cache_key(realm: 'Realm') -> str:
return "realm_text_description:%s" % (realm.string_id,) return f"realm_text_description:{realm.string_id}"
# Called by models.py to flush the stream cache whenever we save a stream # Called by models.py to flush the stream cache whenever we save a stream
# object. # object.
@ -610,7 +609,7 @@ def to_dict_cache_key(message: 'Message', realm_id: Optional[int]=None) -> str:
return to_dict_cache_key_id(message.id) return to_dict_cache_key_id(message.id)
def open_graph_description_cache_key(content: Any, request: HttpRequest) -> str: def open_graph_description_cache_key(content: Any, request: HttpRequest) -> str:
return 'open_graph_description_path:%s' % (make_safe_digest(request.META['PATH_INFO']),) return 'open_graph_description_path:{}'.format(make_safe_digest(request.META['PATH_INFO']))
def flush_message(sender: Any, **kwargs: Any) -> None: def flush_message(sender: Any, **kwargs: Any) -> None:
message = kwargs['instance'] message = kwargs['instance']

View File

@ -8,7 +8,7 @@ def generate_camo_url(url: str) -> str:
encoded_camo_key = settings.CAMO_KEY.encode("utf-8") encoded_camo_key = settings.CAMO_KEY.encode("utf-8")
digest = hmac.new(encoded_camo_key, encoded_url, hashlib.sha1).hexdigest() digest = hmac.new(encoded_camo_key, encoded_url, hashlib.sha1).hexdigest()
hex_encoded_url = binascii.b2a_hex(encoded_url) hex_encoded_url = binascii.b2a_hex(encoded_url)
return "%s/%s" % (digest, hex_encoded_url.decode("utf-8")) return "{}/{}".format(digest, hex_encoded_url.decode("utf-8"))
# Encodes the provided URL using the same algorithm used by the camo # Encodes the provided URL using the same algorithm used by the camo
# caching https image proxy # caching https image proxy
@ -16,7 +16,7 @@ def get_camo_url(url: str) -> str:
# Only encode the url if Camo is enabled # Only encode the url if Camo is enabled
if settings.CAMO_URI == '': if settings.CAMO_URI == '':
return url return url
return "%s%s" % (settings.CAMO_URI, generate_camo_url(url)) return f"{settings.CAMO_URI}{generate_camo_url(url)}"
def is_camo_url_valid(digest: str, url: str) -> bool: def is_camo_url_valid(digest: str, url: str) -> bool:
camo_url = generate_camo_url(url) camo_url = generate_camo_url(url)

View File

@ -33,7 +33,7 @@ def copy_user_settings(source_profile: UserProfile, target_profile: UserProfile)
def get_display_email_address(user_profile: UserProfile, realm: Realm) -> str: def get_display_email_address(user_profile: UserProfile, realm: Realm) -> str:
if not user_profile.email_address_is_realm_public(): if not user_profile.email_address_is_realm_public():
return "user%s@%s" % (user_profile.id, get_fake_email_domain()) return f"user{user_profile.id}@{get_fake_email_domain()}"
return user_profile.delivery_email return user_profile.delivery_email
def get_role_for_new_user(invited_as: int, realm_creation: bool=False) -> int: def get_role_for_new_user(invited_as: int, realm_creation: bool=False) -> int:

View File

@ -23,7 +23,7 @@ def wrapper_execute(self: CursorObj,
stop = time.time() stop = time.time()
duration = stop - start duration = stop - start
self.connection.queries.append({ self.connection.queries.append({
'time': "%.3f" % (duration,), 'time': f"{duration:.3f}",
}) })
class TimeTrackingCursor(cursor): class TimeTrackingCursor(cursor):

View File

@ -146,14 +146,14 @@ def gather_new_streams(user_profile: UserProfile,
else: else:
new_streams = [] new_streams = []
base_url = "%s/#narrow/stream/" % (user_profile.realm.uri,) base_url = f"{user_profile.realm.uri}/#narrow/stream/"
streams_html = [] streams_html = []
streams_plain = [] streams_plain = []
for stream in new_streams: for stream in new_streams:
narrow_url = base_url + encode_stream(stream.id, stream.name) narrow_url = base_url + encode_stream(stream.id, stream.name)
stream_link = "<a href='%s'>%s</a>" % (narrow_url, stream.name) stream_link = f"<a href='{narrow_url}'>{stream.name}</a>"
streams_html.append(stream_link) streams_html.append(stream_link)
streams_plain.append(stream.name) streams_plain.append(stream.name)

View File

@ -69,7 +69,7 @@ def report_to_zulip(error_message: str) -> None:
error_bot, error_bot,
error_stream, error_stream,
"email mirror error", "email mirror error",
"""~~~\n%s\n~~~""" % (error_message,) f"""~~~\n{error_message}\n~~~"""
) )
def log_and_report(email_message: EmailMessage, error_message: str, to: Optional[str]) -> None: def log_and_report(email_message: EmailMessage, error_message: str, to: Optional[str]) -> None:
@ -155,7 +155,7 @@ def construct_zulip_body(message: EmailMessage, realm: Realm, show_sender: bool=
if show_sender: if show_sender:
sender = handle_header_content(message.get("From", "")) sender = handle_header_content(message.get("From", ""))
body = "From: %s\n%s" % (sender, body) body = f"From: {sender}\n{body}"
return body return body
@ -279,7 +279,7 @@ def extract_and_upload_attachments(message: EmailMessage, realm: Realm) -> str:
attachment, attachment,
user_profile, user_profile,
target_realm=realm) target_realm=realm)
formatted_link = "[%s](%s)" % (filename, s3_url) formatted_link = f"[{filename}]({s3_url})"
attachment_links.append(formatted_link) attachment_links.append(formatted_link)
else: else:
logger.warning("Payload is not bytes (invalid attachment %s in message from %s).", logger.warning("Payload is not bytes (invalid attachment %s in message from %s).",

View File

@ -60,7 +60,7 @@ def encode_email_address_helper(name: str, email_token: str, show_sender: bool=F
# If encoded_name ends up empty, we just skip this part of the address: # If encoded_name ends up empty, we just skip this part of the address:
if encoded_name: if encoded_name:
encoded_token = "%s.%s" % (encoded_name, email_token) encoded_token = f"{encoded_name}.{email_token}"
else: else:
encoded_token = email_token encoded_token = email_token

View File

@ -93,16 +93,9 @@ def fix_emojis(content: str, base_url: str, emojiset: str) -> str:
emoji_code = match.group('emoji_code') emoji_code = match.group('emoji_code')
emoji_name = emoji_span_elem.get('title') emoji_name = emoji_span_elem.get('title')
alt_code = emoji_span_elem.text alt_code = emoji_span_elem.text
image_url = base_url + '/static/generated/emoji/images-%(emojiset)s-64/%(emoji_code)s.png' % { image_url = base_url + f'/static/generated/emoji/images-{emojiset}-64/{emoji_code}.png'
'emojiset': emojiset,
'emoji_code': emoji_code
}
img_elem = lxml.html.fromstring( img_elem = lxml.html.fromstring(
'<img alt="%(alt_code)s" src="%(image_url)s" title="%(title)s">' % { f'<img alt="{alt_code}" src="{image_url}" title="{emoji_name}">')
'alt_code': alt_code,
'image_url': image_url,
'title': emoji_name,
})
img_elem.set('style', 'height: 20px;') img_elem.set('style', 'height: 20px;')
img_elem.tail = emoji_span_elem.tail img_elem.tail = emoji_span_elem.tail
return img_elem return img_elem
@ -179,8 +172,8 @@ def build_message_list(user_profile: UserProfile, messages: List[Message]) -> Li
def message_header(user_profile: UserProfile, message: Message) -> Dict[str, Any]: def message_header(user_profile: UserProfile, message: Message) -> Dict[str, Any]:
if message.recipient.type == Recipient.PERSONAL: if message.recipient.type == Recipient.PERSONAL:
narrow_link = get_narrow_url(user_profile, message) narrow_link = get_narrow_url(user_profile, message)
header = "You and %s" % (message.sender.full_name,) header = f"You and {message.sender.full_name}"
header_html = "<a style='color: #ffffff;' href='%s'>%s</a>" % (narrow_link, header) header_html = f"<a style='color: #ffffff;' href='{narrow_link}'>{header}</a>"
elif message.recipient.type == Recipient.HUDDLE: elif message.recipient.type == Recipient.HUDDLE:
display_recipient = get_display_recipient(message.recipient) display_recipient = get_display_recipient(message.recipient)
assert not isinstance(display_recipient, str) assert not isinstance(display_recipient, str)
@ -188,15 +181,14 @@ def build_message_list(user_profile: UserProfile, messages: List[Message]) -> Li
display_recipient=display_recipient) display_recipient=display_recipient)
other_recipients = [r['full_name'] for r in display_recipient other_recipients = [r['full_name'] for r in display_recipient
if r['id'] != user_profile.id] if r['id'] != user_profile.id]
header = "You and %s" % (", ".join(other_recipients),) header = "You and {}".format(", ".join(other_recipients))
header_html = "<a style='color: #ffffff;' href='%s'>%s</a>" % (narrow_link, header) header_html = f"<a style='color: #ffffff;' href='{narrow_link}'>{header}</a>"
else: else:
stream = Stream.objects.only('id', 'name').get(id=message.recipient.type_id) stream = Stream.objects.only('id', 'name').get(id=message.recipient.type_id)
narrow_link = get_narrow_url(user_profile, message, stream=stream) narrow_link = get_narrow_url(user_profile, message, stream=stream)
header = "%s > %s" % (stream.name, message.topic_name()) header = f"{stream.name} > {message.topic_name()}"
stream_link = stream_narrow_url(user_profile.realm, stream) stream_link = stream_narrow_url(user_profile.realm, stream)
header_html = "<a href='%s'>%s</a> > <a href='%s'>%s</a>" % ( header_html = f"<a href='{stream_link}'>{stream.name}</a> > <a href='{narrow_link}'>{message.topic_name()}</a>"
stream_link, stream.name, narrow_link, message.topic_name())
return {"plain": header, return {"plain": header,
"html": header_html, "html": header_html,
"stream_message": message.recipient.type_name() == "stream"} "stream_message": message.recipient.type_name() == "stream"}
@ -371,11 +363,10 @@ def do_send_missedmessage_events_reply_in_zulip(user_profile: UserProfile,
huddle_display_name = " and ".join(other_recipients) huddle_display_name = " and ".join(other_recipients)
context.update({'huddle_display_name': huddle_display_name}) context.update({'huddle_display_name': huddle_display_name})
elif len(other_recipients) == 3: elif len(other_recipients) == 3:
huddle_display_name = "%s, %s, and %s" % ( huddle_display_name = f"{other_recipients[0]}, {other_recipients[1]}, and {other_recipients[2]}"
other_recipients[0], other_recipients[1], other_recipients[2])
context.update({'huddle_display_name': huddle_display_name}) context.update({'huddle_display_name': huddle_display_name})
else: else:
huddle_display_name = "%s, and %s others" % ( huddle_display_name = "{}, and {} others".format(
', '.join(other_recipients[:2]), len(other_recipients) - 2) ', '.join(other_recipients[:2]), len(other_recipients) - 2)
context.update({'huddle_display_name': huddle_display_name}) context.update({'huddle_display_name': huddle_display_name})
elif (missed_messages[0]['message'].recipient.type == Recipient.PERSONAL): elif (missed_messages[0]['message'].recipient.type == Recipient.PERSONAL):
@ -388,7 +379,7 @@ def do_send_missedmessage_events_reply_in_zulip(user_profile: UserProfile,
m['trigger'] == 'wildcard_mentioned'}) m['trigger'] == 'wildcard_mentioned'})
message = missed_messages[0]['message'] message = missed_messages[0]['message']
stream = Stream.objects.only('id', 'name').get(id=message.recipient.type_id) stream = Stream.objects.only('id', 'name').get(id=message.recipient.type_id)
stream_header = "%s > %s" % (stream.name, message.topic_name()) stream_header = f"{stream.name} > {message.topic_name()}"
context.update({ context.update({
'stream_header': stream_header, 'stream_header': stream_header,
}) })

View File

@ -112,7 +112,7 @@ def validate_email_is_valid(
return None return None
def email_reserved_for_system_bots_error(email: str) -> str: def email_reserved_for_system_bots_error(email: str) -> str:
return '%s is reserved for system bots' % (email,) return f'{email} is reserved for system bots'
def get_existing_user_errors( def get_existing_user_errors(
target_realm: Realm, target_realm: Realm,

View File

@ -34,7 +34,7 @@ def user_info_str(report: Dict[str, Any]) -> str:
def deployment_repr(report: Dict[str, Any]) -> str: def deployment_repr(report: Dict[str, Any]) -> str:
deployment = 'Deployed code:\n' deployment = 'Deployed code:\n'
for field, val in report['deployment_data'].items(): for field, val in report['deployment_data'].items():
deployment += '- %s: %s\n' % (field, val) deployment += f'- {field}: {val}\n'
return deployment return deployment
def notify_browser_error(report: Dict[str, Any]) -> None: def notify_browser_error(report: Dict[str, Any]) -> None:
@ -44,7 +44,7 @@ def notify_browser_error(report: Dict[str, Any]) -> None:
email_browser_error(report) email_browser_error(report)
def email_browser_error(report: Dict[str, Any]) -> None: def email_browser_error(report: Dict[str, Any]) -> None:
email_subject = "Browser error for %s" % (user_info_str(report),) email_subject = f"Browser error for {user_info_str(report)}"
body = ("User: %(user_full_name)s <%(user_email)s> on %(deployment)s\n\n" body = ("User: %(user_full_name)s <%(user_email)s> on %(deployment)s\n\n"
"Message:\n%(message)s\n\nStacktrace:\n%(stacktrace)s\n\n" "Message:\n%(message)s\n\nStacktrace:\n%(stacktrace)s\n\n"
@ -59,18 +59,18 @@ def email_browser_error(report: Dict[str, Any]) -> None:
if more_info is not None: if more_info is not None:
body += "\nAdditional information:" body += "\nAdditional information:"
for (key, value) in more_info.items(): for (key, value) in more_info.items():
body += "\n %s: %s" % (key, value) body += f"\n {key}: {value}"
body += "\n\nLog:\n%s" % (report['log'],) body += "\n\nLog:\n{}".format(report['log'])
mail_admins(email_subject, body) mail_admins(email_subject, body)
def zulip_browser_error(report: Dict[str, Any]) -> None: def zulip_browser_error(report: Dict[str, Any]) -> None:
email_subject = "JS error: %s" % (report['user_email'],) email_subject = "JS error: {}".format(report['user_email'])
user_info = user_info_str(report) user_info = user_info_str(report)
body = "User: %s\n" % (user_info,) body = f"User: {user_info}\n"
body += ("Message: %(message)s\n" body += ("Message: %(message)s\n"
% dict(report)) % dict(report))
@ -108,7 +108,7 @@ def zulip_server_error(report: Dict[str, Any]) -> None:
val = report.get(field.lower()) val = report.get(field.lower())
if field == "QUERY_STRING": if field == "QUERY_STRING":
val = clean_data_from_query_parameters(str(val)) val = clean_data_from_query_parameters(str(val))
request_repr += "- %s: \"%s\"\n" % (field, val) request_repr += f"- {field}: \"{val}\"\n"
request_repr += "~~~~" request_repr += "~~~~"
else: else:
request_repr = "Request info: none" request_repr = "Request info: none"
@ -144,7 +144,7 @@ def email_server_error(report: Dict[str, Any]) -> None:
val = report.get(field.lower()) val = report.get(field.lower())
if field == "QUERY_STRING": if field == "QUERY_STRING":
val = clean_data_from_query_parameters(str(val)) val = clean_data_from_query_parameters(str(val))
request_repr += "- %s: \"%s\"\n" % (field, val) request_repr += f"- {field}: \"{val}\"\n"
else: else:
request_repr = "Request info: none\n" request_repr = "Request info: none\n"

View File

@ -818,7 +818,7 @@ def apply_event(state: Dict[str, Any],
elif event['type'] == 'has_zoom_token': elif event['type'] == 'has_zoom_token':
state['has_zoom_token'] = event['value'] state['has_zoom_token'] = event['value']
else: else:
raise AssertionError("Unexpected event type %s" % (event['type'],)) raise AssertionError("Unexpected event type {}".format(event['type']))
def do_events_register(user_profile: UserProfile, user_client: Client, def do_events_register(user_profile: UserProfile, user_client: Client,
apply_markdown: bool = True, apply_markdown: bool = True,

View File

@ -420,13 +420,13 @@ class Config:
using id_source.''') using id_source.''')
if self.id_source[0] != self.virtual_parent.table: if self.id_source[0] != self.virtual_parent.table:
raise AssertionError(''' raise AssertionError('''
Configuration error. To populate %s, you Configuration error. To populate {}, you
want data from %s, but that differs from want data from {}, but that differs from
the table name of your virtual parent (%s), the table name of your virtual parent ({}),
which suggests you many not have set up which suggests you many not have set up
the ordering correctly. You may simply the ordering correctly. You may simply
need to assign a virtual_parent, or there need to assign a virtual_parent, or there
may be deeper issues going on.''' % ( may be deeper issues going on.'''.format(
self.table, self.table,
self.id_source[0], self.id_source[0],
self.virtual_parent.table)) self.virtual_parent.table))
@ -466,7 +466,7 @@ def export_from_config(response: TableData, config: Config, seed_object: Optiona
if config.custom_tables: if config.custom_tables:
for t in config.custom_tables: for t in config.custom_tables:
if t not in response: if t not in response:
raise AssertionError('Custom fetch failed to populate %s' % (t,)) raise AssertionError(f'Custom fetch failed to populate {t}')
elif config.concat_and_destroy: elif config.concat_and_destroy:
# When we concat_and_destroy, we are working with # When we concat_and_destroy, we are working with
@ -1177,16 +1177,16 @@ def _check_key_metadata(email_gateway_bot: Optional[UserProfile],
# Helper function for export_files_from_s3 # Helper function for export_files_from_s3
if 'realm_id' in key.metadata and key.metadata['realm_id'] != str(realm.id): if 'realm_id' in key.metadata and key.metadata['realm_id'] != str(realm.id):
if email_gateway_bot is None or key.metadata['user_profile_id'] != str(email_gateway_bot.id): if email_gateway_bot is None or key.metadata['user_profile_id'] != str(email_gateway_bot.id):
raise AssertionError("Key metadata problem: %s %s / %s" % (key.name, key.metadata, realm.id)) raise AssertionError(f"Key metadata problem: {key.name} {key.metadata} / {realm.id}")
# Email gateway bot sends messages, potentially including attachments, cross-realm. # Email gateway bot sends messages, potentially including attachments, cross-realm.
print("File uploaded by email gateway bot: %s / %s" % (key.key, key.metadata)) print(f"File uploaded by email gateway bot: {key.key} / {key.metadata}")
elif processing_avatars: elif processing_avatars:
if 'user_profile_id' not in key.metadata: if 'user_profile_id' not in key.metadata:
raise AssertionError("Missing user_profile_id in key metadata: %s" % (key.metadata,)) raise AssertionError(f"Missing user_profile_id in key metadata: {key.metadata}")
if int(key.metadata['user_profile_id']) not in user_ids: if int(key.metadata['user_profile_id']) not in user_ids:
raise AssertionError("Wrong user_profile_id in key metadata: %s" % (key.metadata,)) raise AssertionError(f"Wrong user_profile_id in key metadata: {key.metadata}")
elif 'realm_id' not in key.metadata: elif 'realm_id' not in key.metadata:
raise AssertionError("Missing realm_id in key metadata: %s" % (key.metadata,)) raise AssertionError(f"Missing realm_id in key metadata: {key.metadata}")
def _get_exported_s3_record( def _get_exported_s3_record(
bucket_name: str, bucket_name: str,
@ -1233,11 +1233,11 @@ def _save_s3_object_to_file(key: ServiceResource, output_dir: str, processing_av
else: else:
fields = key.key.split('/') fields = key.key.split('/')
if len(fields) != 3: if len(fields) != 3:
raise AssertionError("Suspicious key with invalid format %s" % (key.key,)) raise AssertionError(f"Suspicious key with invalid format {key.key}")
filename = os.path.join(output_dir, key.key) filename = os.path.join(output_dir, key.key)
if "../" in filename: if "../" in filename:
raise AssertionError("Suspicious file with invalid format %s" % (filename,)) raise AssertionError(f"Suspicious file with invalid format {filename}")
dirname = os.path.dirname(filename) dirname = os.path.dirname(filename)
if not os.path.exists(dirname): if not os.path.exists(dirname):
@ -1264,11 +1264,11 @@ def export_files_from_s3(realm: Realm, bucket_name: str, output_dir: Path,
user_ids.add(user_profile.id) user_ids.add(user_profile.id)
if processing_realm_icon_and_logo: if processing_realm_icon_and_logo:
object_prefix = "%s/realm/" % (realm.id,) object_prefix = f"{realm.id}/realm/"
elif processing_emoji: elif processing_emoji:
object_prefix = "%s/emoji/images/" % (realm.id,) object_prefix = f"{realm.id}/emoji/images/"
else: else:
object_prefix = "%s/" % (realm.id,) object_prefix = f"{realm.id}/"
if settings.EMAIL_GATEWAY_BOT is not None: if settings.EMAIL_GATEWAY_BOT is not None:
email_gateway_bot: Optional[UserProfile] = get_system_bot(settings.EMAIL_GATEWAY_BOT) email_gateway_bot: Optional[UserProfile] = get_system_bot(settings.EMAIL_GATEWAY_BOT)
@ -1576,7 +1576,7 @@ def launch_user_message_subprocesses(threads: int, output_dir: Path,
while pids: while pids:
pid, status = os.wait() pid, status = os.wait()
shard = pids.pop(pid) shard = pids.pop(pid)
print('Shard %s finished, status %s' % (shard, status)) print(f'Shard {shard} finished, status {status}')
def do_export_user(user_profile: UserProfile, output_dir: Path) -> None: def do_export_user(user_profile: UserProfile, output_dir: Path) -> None:
response: TableData = {} response: TableData = {}
@ -1741,8 +1741,8 @@ def export_realm_wrapper(realm: Realm, output_dir: str,
tarball_path = do_export_realm(realm=realm, output_dir=output_dir, tarball_path = do_export_realm(realm=realm, output_dir=output_dir,
threads=threads, public_only=public_only, threads=threads, public_only=public_only,
consent_message_id=consent_message_id) consent_message_id=consent_message_id)
print("Finished exporting to %s" % (output_dir,)) print(f"Finished exporting to {output_dir}")
print("Tarball written to %s" % (tarball_path,)) print(f"Tarball written to {tarball_path}")
if not upload: if not upload:
return None return None
@ -1753,11 +1753,11 @@ def export_realm_wrapper(realm: Realm, output_dir: str,
print("Uploading export tarball...") print("Uploading export tarball...")
public_url = zerver.lib.upload.upload_backend.upload_export_tarball(realm, tarball_path) public_url = zerver.lib.upload.upload_backend.upload_export_tarball(realm, tarball_path)
print() print()
print("Uploaded to %s" % (public_url,)) print(f"Uploaded to {public_url}")
if delete_after_upload: if delete_after_upload:
os.remove(tarball_path) os.remove(tarball_path)
print("Successfully deleted the tarball at %s" % (tarball_path,)) print(f"Successfully deleted the tarball at {tarball_path}")
return public_url return public_url
def get_realm_exports_serialized(user: UserProfile) -> List[Dict[str, Any]]: def get_realm_exports_serialized(user: UserProfile) -> List[Dict[str, Any]]:

View File

@ -4,7 +4,7 @@ from lxml.html.diff import htmldiff
from typing import Optional from typing import Optional
def highlight_with_class(text: str, klass: str) -> str: def highlight_with_class(text: str, klass: str) -> str:
return '<span class="%s">%s</span>' % (klass, text) return f'<span class="{klass}">{text}</span>'
def highlight_html_differences(s1: str, s2: str, msg_id: Optional[int]=None) -> str: def highlight_html_differences(s1: str, s2: str, msg_id: Optional[int]=None) -> str:
retval = htmldiff(s1, s2) retval = htmldiff(s1, s2)

View File

@ -101,10 +101,10 @@ path_maps: Dict[str, Dict[str, str]] = {
def update_id_map(table: TableName, old_id: int, new_id: int) -> None: def update_id_map(table: TableName, old_id: int, new_id: int) -> None:
if table not in ID_MAP: if table not in ID_MAP:
raise Exception(''' raise Exception('''
Table %s is not initialized in ID_MAP, which could Table {} is not initialized in ID_MAP, which could
mean that we have not thought through circular mean that we have not thought through circular
dependencies. dependencies.
''' % (table,)) '''.format(table))
ID_MAP[table][old_id] = new_id ID_MAP[table][old_id] = new_id
def fix_datetime_fields(data: TableData, table: TableName) -> None: def fix_datetime_fields(data: TableData, table: TableName) -> None:

View File

@ -70,7 +70,7 @@ class _RateLimitFilter:
try: try:
# Track duplicate errors # Track duplicate errors
duplicate = False duplicate = False
rate = getattr(settings, '%s_LIMIT' % (self.__class__.__name__.upper(),), rate = getattr(settings, f'{self.__class__.__name__.upper()}_LIMIT',
600) # seconds 600) # seconds
if rate > 0: if rate > 0:

View File

@ -28,7 +28,7 @@ def check_config() -> None:
except AttributeError: except AttributeError:
pass pass
raise CommandError("Error: You must set %s in /etc/zulip/settings.py." % (setting_name,)) raise CommandError(f"Error: You must set {setting_name} in /etc/zulip/settings.py.")
def sleep_forever() -> None: def sleep_forever() -> None:
while True: # nocoverage while True: # nocoverage
@ -127,7 +127,7 @@ You can use the command list_realms to find ID of the realms in this server."""
return UserProfile.objects.select_related().get( return UserProfile.objects.select_related().get(
delivery_email__iexact=email.strip(), realm=realm) delivery_email__iexact=email.strip(), realm=realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
raise CommandError("The realm '%s' does not contain a user with email '%s'" % (realm, email)) raise CommandError(f"The realm '{realm}' does not contain a user with email '{email}'")
# Realm is None in the remaining code path. Here, we # Realm is None in the remaining code path. Here, we
# optimistically try to see if there is exactly one user with # optimistically try to see if there is exactly one user with
@ -139,7 +139,7 @@ You can use the command list_realms to find ID of the realms in this server."""
"(in different realms); please pass `--realm` " "(in different realms); please pass `--realm` "
"to specify which one to modify.") "to specify which one to modify.")
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
raise CommandError("This Zulip server does not contain a user with email '%s'" % (email,)) raise CommandError(f"This Zulip server does not contain a user with email '{email}'")
def get_client(self) -> Client: def get_client(self) -> Client:
"""Returns a Zulip Client object to be used for things done in management commands""" """Returns a Zulip Client object to be used for things done in management commands"""

View File

@ -519,7 +519,7 @@ class MessageDict:
elif recip['email'] > display_recipient[0]['email']: elif recip['email'] > display_recipient[0]['email']:
display_recipient = [display_recipient[0], recip] display_recipient = [display_recipient[0], recip]
else: else:
raise AssertionError("Invalid recipient type %s" % (recipient_type,)) raise AssertionError(f"Invalid recipient type {recipient_type}")
obj['display_recipient'] = display_recipient obj['display_recipient'] = display_recipient
obj['type'] = display_type obj['type'] = display_type
@ -1019,7 +1019,7 @@ def apply_unread_message_event(user_profile: UserProfile,
else: else:
message_type = 'huddle' message_type = 'huddle'
else: else:
raise AssertionError("Invalid message type %s" % (message['type'],)) raise AssertionError("Invalid message type {}".format(message['type']))
sender_id = message['sender_id'] sender_id = message['sender_id']

View File

@ -28,11 +28,11 @@ def do_batch_update(cursor: CursorObj,
if min_id is None: if min_id is None:
return return
print("\n Range of rows to update: [%s, %s]" % (min_id, max_id)) print(f"\n Range of rows to update: [{min_id}, {max_id}]")
while min_id <= max_id: while min_id <= max_id:
lower = min_id lower = min_id
upper = min_id + batch_size upper = min_id + batch_size
print(' Updating range [%s,%s)' % (lower, upper)) print(f' Updating range [{lower},{upper})')
cursor.execute(stmt, [lower, upper]) cursor.execute(stmt, [lower, upper])
min_id = upper min_id = upper

View File

@ -15,7 +15,7 @@ def xor_hex_strings(bytes_a: str, bytes_b: str) -> str:
"""Given two hex strings of equal length, return a hex string with """Given two hex strings of equal length, return a hex string with
the bitwise xor of the two hex strings.""" the bitwise xor of the two hex strings."""
assert len(bytes_a) == len(bytes_b) assert len(bytes_a) == len(bytes_b)
return ''.join(["%x" % (int(x, 16) ^ int(y, 16),) return ''.join([f"{int(x, 16) ^ int(y, 16):x}"
for x, y in zip(bytes_a, bytes_b)]) for x, y in zip(bytes_a, bytes_b)])
def ascii_to_hex(input_string: str) -> str: def ascii_to_hex(input_string: str) -> str:

View File

@ -223,11 +223,11 @@ def notify_bot_owner(event: Dict[str, Any],
bot_id = event['user_profile_id'] bot_id = event['user_profile_id']
bot_owner = get_user_profile_by_id(bot_id).bot_owner bot_owner = get_user_profile_by_id(bot_id).bot_owner
notification_message = "[A message](%s) triggered an outgoing webhook." % (message_url,) notification_message = f"[A message]({message_url}) triggered an outgoing webhook."
if failure_message: if failure_message:
notification_message += "\n" + failure_message notification_message += "\n" + failure_message
if status_code: if status_code:
notification_message += "\nThe webhook got a response with status code *%s*." % (status_code,) notification_message += f"\nThe webhook got a response with status code *{status_code}*."
if response_content: if response_content:
notification_message += "\nThe response contains the following payload:\n" \ notification_message += "\nThe response contains the following payload:\n" \
"```\n%s\n```" % (str(response_content),) "```\n%s\n```" % (str(response_content),)
@ -326,6 +326,6 @@ def do_rest_call(base_url: str,
response_message = ("An exception of type *%s* occurred for message `%s`! " response_message = ("An exception of type *%s* occurred for message `%s`! "
"See the Zulip server logs for more information." % ( "See the Zulip server logs for more information." % (
type(e).__name__, event["command"],)) type(e).__name__, event["command"],))
logging.exception("Outhook trigger failed:\n %s" % (e,)) logging.exception(f"Outhook trigger failed:\n {e}")
fail_with_message(event, response_message) fail_with_message(event, response_message)
notify_bot_owner(event, exception=e) notify_bot_owner(event, exception=e)

View File

@ -468,14 +468,14 @@ def get_gcm_alert(message: Message) -> str:
""" """
sender_str = message.sender.full_name sender_str = message.sender.full_name
if message.recipient.type == Recipient.HUDDLE and message.trigger == 'private_message': if message.recipient.type == Recipient.HUDDLE and message.trigger == 'private_message':
return "New private group message from %s" % (sender_str,) return f"New private group message from {sender_str}"
elif message.recipient.type == Recipient.PERSONAL and message.trigger == 'private_message': elif message.recipient.type == Recipient.PERSONAL and message.trigger == 'private_message':
return "New private message from %s" % (sender_str,) return f"New private message from {sender_str}"
elif message.is_stream_message() and (message.trigger == 'mentioned' or elif message.is_stream_message() and (message.trigger == 'mentioned' or
message.trigger == 'wildcard_mentioned'): message.trigger == 'wildcard_mentioned'):
return "New mention from %s" % (sender_str,) return f"New mention from {sender_str}"
else: # message.is_stream_message() and message.trigger == 'stream_push_notify' else: # message.is_stream_message() and message.trigger == 'stream_push_notify'
return "New stream message from %s in %s" % (sender_str, get_display_recipient(message.recipient),) return f"New stream message from {sender_str} in {get_display_recipient(message.recipient)}"
def get_mobile_push_content(rendered_content: str) -> str: def get_mobile_push_content(rendered_content: str) -> str:
def get_text(elem: lxml.html.HtmlElement) -> str: def get_text(elem: lxml.html.HtmlElement) -> str:
@ -586,7 +586,7 @@ def get_apns_alert_title(message: Message) -> str:
assert isinstance(recipients, list) assert isinstance(recipients, list)
return ', '.join(sorted(r['full_name'] for r in recipients)) return ', '.join(sorted(r['full_name'] for r in recipients))
elif message.is_stream_message(): elif message.is_stream_message():
return "#%s > %s" % (get_display_recipient(message.recipient), message.topic_name(),) return f"#{get_display_recipient(message.recipient)} > {message.topic_name()}"
# For personal PMs, we just show the sender name. # For personal PMs, we just show the sender name.
return message.sender.full_name return message.sender.full_name

View File

@ -38,7 +38,7 @@ class SimpleQueueClient:
start = time.time() start = time.time()
self.connection = pika.BlockingConnection(self._get_parameters()) self.connection = pika.BlockingConnection(self._get_parameters())
self.channel = self.connection.channel() self.channel = self.connection.channel()
self.log.info('SimpleQueueClient connected (connecting took %.3fs)' % (time.time() - start,)) self.log.info(f'SimpleQueueClient connected (connecting took {time.time() - start:.3f}s)')
def _reconnect(self) -> None: def _reconnect(self) -> None:
self.connection = None self.connection = None
@ -76,10 +76,10 @@ class SimpleQueueClient:
credentials=credentials) credentials=credentials)
def _generate_ctag(self, queue_name: str) -> str: def _generate_ctag(self, queue_name: str) -> str:
return "%s_%s" % (queue_name, str(random.getrandbits(16))) return f"{queue_name}_{str(random.getrandbits(16))}"
def _reconnect_consumer_callback(self, queue: str, consumer: Consumer) -> None: def _reconnect_consumer_callback(self, queue: str, consumer: Consumer) -> None:
self.log.info("Queue reconnecting saved consumer %s to queue %s" % (consumer, queue)) self.log.info(f"Queue reconnecting saved consumer {consumer} to queue {queue}")
self.ensure_queue(queue, lambda: self.channel.basic_consume(queue, self.ensure_queue(queue, lambda: self.channel.basic_consume(queue,
consumer, consumer,
consumer_tag=self._generate_ctag(queue))) consumer_tag=self._generate_ctag(queue)))
@ -115,7 +115,7 @@ class SimpleQueueClient:
properties=pika.BasicProperties(delivery_mode=2), properties=pika.BasicProperties(delivery_mode=2),
body=body) body=body)
statsd.incr("rabbitmq.publish.%s" % (queue_name,)) statsd.incr(f"rabbitmq.publish.{queue_name}")
self.ensure_queue(queue_name, do_publish) self.ensure_queue(queue_name, do_publish)

View File

@ -286,7 +286,7 @@ class TornadoInMemoryRateLimiterBackend(RateLimiterBackend):
ratelimited, time_till_free = cls.need_to_limit(entity_key, time_window, max_count) ratelimited, time_till_free = cls.need_to_limit(entity_key, time_window, max_count)
if ratelimited: if ratelimited:
statsd.incr("ratelimiter.limited.%s" % (entity_key,)) statsd.incr(f"ratelimiter.limited.{entity_key}")
break break
return ratelimited, time_till_free return ratelimited, time_till_free
@ -450,7 +450,7 @@ class RedisRateLimiterBackend(RateLimiterBackend):
ratelimited, time = cls.is_ratelimited(entity_key, rules) ratelimited, time = cls.is_ratelimited(entity_key, rules)
if ratelimited: if ratelimited:
statsd.incr("ratelimiter.limited.%s" % (entity_key,)) statsd.incr(f"ratelimiter.limited.{entity_key}")
else: else:
try: try:

View File

@ -12,6 +12,6 @@ def get_realm_icon_url(realm: Realm) -> str:
return upload_backend.get_realm_icon_url(realm.id, realm.icon_version) return upload_backend.get_realm_icon_url(realm.id, realm.icon_version)
elif settings.ENABLE_GRAVATAR: elif settings.ENABLE_GRAVATAR:
hash_key = gravatar_hash(realm.string_id) hash_key = gravatar_hash(realm.string_id)
return "https://secure.gravatar.com/avatar/%s?d=identicon" % (hash_key,) return f"https://secure.gravatar.com/avatar/{hash_key}?d=identicon"
else: else:
return settings.DEFAULT_AVATAR_URI+'?version=0' return settings.DEFAULT_AVATAR_URI+'?version=0'

View File

@ -63,4 +63,4 @@ def validate_key_fits_format(key: str, key_format: str) -> None:
regex = key_format.format(token=r"[a-zA-Z0-9]+") regex = key_format.format(token=r"[a-zA-Z0-9]+")
if not re.fullmatch(regex, key): if not re.fullmatch(regex, key):
raise ZulipRedisKeyOfWrongFormatError("%s does not match format %s" % (key, key_format)) raise ZulipRedisKeyOfWrongFormatError(f"{key} does not match format {key_format}")

Some files were not shown because too many files have changed in this diff Show More