diff --git a/analytics/views/installation_activity.py b/analytics/views/installation_activity.py
index 4bfd97e369..5588ddbf09 100644
--- a/analytics/views/installation_activity.py
+++ b/analytics/views/installation_activity.py
@@ -73,26 +73,24 @@ def get_realm_day_counts() -> Dict[str, Dict[str, Markup]]:
for row in rows:
counts[row["string_id"]][row["age"]] = row["cnt"]
+ def format_count(cnt: int, style: Optional[str] = None) -> Markup:
+ if style is not None:
+ good_bad = style
+ elif cnt == min_cnt:
+ good_bad = "bad"
+ elif cnt == max_cnt:
+ good_bad = "good"
+ else:
+ good_bad = "neutral"
+
+ return Markup('
{cnt} | ').format(good_bad=good_bad, cnt=cnt)
+
result = {}
for string_id in counts:
raw_cnts = [counts[string_id].get(age, 0) for age in range(8)]
min_cnt = min(raw_cnts[1:])
max_cnt = max(raw_cnts[1:])
- def format_count(cnt: int, style: Optional[str] = None) -> Markup:
- if style is not None:
- good_bad = style
- elif cnt == min_cnt:
- good_bad = "bad"
- elif cnt == max_cnt:
- good_bad = "good"
- else:
- good_bad = "neutral"
-
- return Markup('{cnt} | ').format(
- good_bad=good_bad, cnt=cnt
- )
-
cnts = format_count(raw_cnts[0], "neutral") + Markup().join(map(format_count, raw_cnts[1:]))
result[string_id] = dict(cnts=cnts)
diff --git a/pyproject.toml b/pyproject.toml
index cd7ba7f33f..8df41bfc71 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -134,7 +134,6 @@ ignore = [
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
"B007", # Loop control variable not used within the loop body
"B008", # Do not perform function calls in argument defaults
- "B023", # Function definition does not bind loop variable
"B904", # Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
"C408", # Unnecessary `dict` call (rewrite as a literal)
"COM812", # Trailing comma missing
diff --git a/tools/lib/pretty_print.py b/tools/lib/pretty_print.py
index 4c1db87982..47d2b551a4 100644
--- a/tools/lib/pretty_print.py
+++ b/tools/lib/pretty_print.py
@@ -107,6 +107,10 @@ def adjust_block_indentation(tokens: List[Token], fn: str) -> None:
def fix_indents_for_multi_line_tags(tokens: List[Token]) -> None:
+ def fix(frag: str) -> str:
+ frag = frag.strip()
+ return continue_indent + frag if frag else ""
+
for token in tokens:
if token.kind == "code":
continue
@@ -121,10 +125,6 @@ def fix_indents_for_multi_line_tags(tokens: List[Token]) -> None:
frags = token.new_s.split("\n")
- def fix(frag: str) -> str:
- frag = frag.strip()
- return continue_indent + frag if frag else ""
-
token.new_s = frags[0] + "\n" + "\n".join(fix(frag) for frag in frags[1:])
diff --git a/tools/lib/template_parser.py b/tools/lib/template_parser.py
index 0841b3e9d7..08dce7fb01 100644
--- a/tools/lib/template_parser.py
+++ b/tools/lib/template_parser.py
@@ -489,6 +489,20 @@ def validate(fn: Optional[str] = None, text: Optional[str] = None) -> List[Token
def ensure_matching_indentation(fn: str, tokens: List[Token], lines: List[str]) -> None:
+ def has_bad_indentation() -> bool:
+ is_inline_tag = start_tag in HTML_INLINE_TAGS and start_token.kind == "html_start"
+
+ if end_line > start_line + 1:
+ if is_inline_tag:
+ end_row_text = lines[end_line - 1]
+ if end_row_text.lstrip().startswith(end_token.s) and end_col != start_col:
+ return True
+ else:
+ if end_col != start_col:
+ return True
+
+ return False
+
for token in tokens:
if token.start_token is None:
continue
@@ -503,20 +517,6 @@ def ensure_matching_indentation(fn: str, tokens: List[Token], lines: List[str])
end_line = end_token.line
end_col = end_token.col
- def has_bad_indentation() -> bool:
- is_inline_tag = start_tag in HTML_INLINE_TAGS and start_token.kind == "html_start"
-
- if end_line > start_line + 1:
- if is_inline_tag:
- end_row_text = lines[end_line - 1]
- if end_row_text.lstrip().startswith(end_token.s) and end_col != start_col:
- return True
- else:
- if end_col != start_col:
- return True
-
- return False
-
if has_bad_indentation():
raise TemplateParserError(
f"""
diff --git a/zerver/lib/subscription_info.py b/zerver/lib/subscription_info.py
index 971e458073..1be14acc2a 100644
--- a/zerver/lib/subscription_info.py
+++ b/zerver/lib/subscription_info.py
@@ -316,6 +316,9 @@ def bulk_get_subscriber_user_ids(
) -> Dict[int, List[int]]:
"""sub_dict maps stream_id => whether the user is subscribed to that stream."""
target_stream_dicts = []
+ is_subscribed: bool
+ check_user_subscribed = lambda user_profile: is_subscribed
+
for stream_dict in stream_dicts:
stream_id = stream_dict["id"]
is_subscribed = stream_id in subscribed_stream_ids
@@ -324,7 +327,7 @@ def bulk_get_subscriber_user_ids(
validate_user_access_to_subscribers_helper(
user_profile,
stream_dict,
- lambda user_profile: is_subscribed,
+ check_user_subscribed,
)
except JsonableError:
continue
diff --git a/zerver/management/commands/check_redis.py b/zerver/management/commands/check_redis.py
index e5f871eca3..6a5e62eb1e 100644
--- a/zerver/management/commands/check_redis.py
+++ b/zerver/management/commands/check_redis.py
@@ -4,6 +4,7 @@ from typing import Any, Callable, Optional
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError, CommandParser
+from returns.curry import partial
from zerver.lib.rate_limiter import RateLimitedUser, client
from zerver.models import get_user_profile_by_id
@@ -61,7 +62,7 @@ than max_api_calls! (trying to trim) %s %s",
lists = client.keys(wildcard_list)
for list_name in lists:
- self._check_within_range(list_name, lambda: client.llen(list_name), trim_func)
+ self._check_within_range(list_name, partial(client.llen, list_name), trim_func)
zsets = client.keys(wildcard_zset)
for zset in zsets:
@@ -70,5 +71,7 @@ than max_api_calls! (trying to trim) %s %s",
# elements to trim. We'd have to go through every list item and take
# the intersection. The best we can do is expire it
self._check_within_range(
- zset, lambda: client.zcount(zset, 0, now), lambda key, max_calls: None
+ zset,
+ partial(client.zcount, zset, 0, now),
+ lambda key, max_calls: None,
)
diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py
index c10d5ee430..503a00b65b 100644
--- a/zerver/tests/test_events.py
+++ b/zerver/tests/test_events.py
@@ -14,6 +14,7 @@ from unittest import mock
import orjson
from dateutil.parser import parse as dateparser
from django.utils.timezone import now as timezone_now
+from returns.curry import partial
from zerver.actions.alert_words import do_add_alert_words, do_remove_alert_words
from zerver.actions.bots import (
@@ -457,21 +458,21 @@ class NormalActionsTest(BaseAction):
for i in range(3):
content = "mentioning... @**" + user.full_name + "** hello " + str(i)
self.verify_action(
- lambda: self.send_stream_message(self.example_user("cordelia"), "Verona", content),
+ partial(self.send_stream_message, self.example_user("cordelia"), "Verona", content),
)
def test_topic_wildcard_mentioned_send_message_events(self) -> None:
for i in range(3):
content = "mentioning... @**topic** hello " + str(i)
self.verify_action(
- lambda: self.send_stream_message(self.example_user("cordelia"), "Verona", content),
+ partial(self.send_stream_message, self.example_user("cordelia"), "Verona", content),
)
def test_stream_wildcard_mentioned_send_message_events(self) -> None:
for i in range(3):
content = "mentioning... @**all** hello " + str(i)
self.verify_action(
- lambda: self.send_stream_message(self.example_user("cordelia"), "Verona", content),
+ partial(self.send_stream_message, self.example_user("cordelia"), "Verona", content),
)
def test_pm_send_message_events(self) -> None:
@@ -747,12 +748,12 @@ class NormalActionsTest(BaseAction):
)
self.verify_action(
- lambda: do_update_message_flags(user_profile, "add", "read", [message]),
+ partial(do_update_message_flags, user_profile, "add", "read", [message]),
state_change_expected=True,
)
events = self.verify_action(
- lambda: do_update_message_flags(user_profile, "remove", "read", [message]),
+ partial(do_update_message_flags, user_profile, "remove", "read", [message]),
state_change_expected=True,
)
check_update_message_flags_remove("events[0]", events[0])
@@ -761,12 +762,14 @@ class NormalActionsTest(BaseAction):
from_user=user_profile, to_user=self.example_user("cordelia"), content=content
)
self.verify_action(
- lambda: do_update_message_flags(user_profile, "add", "read", [personal_message]),
+ partial(do_update_message_flags, user_profile, "add", "read", [personal_message]),
state_change_expected=True,
)
events = self.verify_action(
- lambda: do_update_message_flags(user_profile, "remove", "read", [personal_message]),
+ partial(
+ do_update_message_flags, user_profile, "remove", "read", [personal_message]
+ ),
state_change_expected=True,
)
check_update_message_flags_remove("events[0]", events[0])
@@ -778,12 +781,12 @@ class NormalActionsTest(BaseAction):
)
self.verify_action(
- lambda: do_update_message_flags(user_profile, "add", "read", [huddle_message]),
+ partial(do_update_message_flags, user_profile, "add", "read", [huddle_message]),
state_change_expected=True,
)
events = self.verify_action(
- lambda: do_update_message_flags(user_profile, "remove", "read", [huddle_message]),
+ partial(do_update_message_flags, user_profile, "remove", "read", [huddle_message]),
state_change_expected=True,
)
check_update_message_flags_remove("events[0]", events[0])
@@ -1712,8 +1715,11 @@ class NormalActionsTest(BaseAction):
):
with fake_backends():
events = self.verify_action(
- lambda: do_set_realm_authentication_methods(
- self.user_profile.realm, auth_method_dict, acting_user=None
+ partial(
+ do_set_realm_authentication_methods,
+ self.user_profile.realm,
+ auth_method_dict,
+ acting_user=None,
)
)
@@ -1727,8 +1733,14 @@ class NormalActionsTest(BaseAction):
)
for pinned in (True, False):
events = self.verify_action(
- lambda: do_change_subscription_property(
- self.user_profile, sub, stream, "pin_to_top", pinned, acting_user=None
+ partial(
+ do_change_subscription_property,
+ self.user_profile,
+ sub,
+ stream,
+ "pin_to_top",
+ pinned,
+ acting_user=None,
)
)
check_subscription_update(
@@ -1795,8 +1807,14 @@ class NormalActionsTest(BaseAction):
# First test with notification_settings_null enabled
for value in (True, False):
events = self.verify_action(
- lambda: do_change_subscription_property(
- self.user_profile, sub, stream, setting_name, value, acting_user=None
+ partial(
+ do_change_subscription_property,
+ self.user_profile,
+ sub,
+ stream,
+ setting_name,
+ value,
+ acting_user=None,
),
notification_settings_null=True,
)
@@ -1809,8 +1827,14 @@ class NormalActionsTest(BaseAction):
for value in (True, False):
events = self.verify_action(
- lambda: do_change_subscription_property(
- self.user_profile, sub, stream, setting_name, value, acting_user=None
+ partial(
+ do_change_subscription_property,
+ self.user_profile,
+ sub,
+ stream,
+ setting_name,
+ value,
+ acting_user=None,
)
)
check_subscription_update(
@@ -1825,7 +1849,8 @@ class NormalActionsTest(BaseAction):
for notifications_stream, notifications_stream_id in ((stream, stream.id), (None, -1)):
events = self.verify_action(
- lambda: do_set_realm_notifications_stream(
+ partial(
+ do_set_realm_notifications_stream,
self.user_profile.realm,
notifications_stream,
notifications_stream_id,
@@ -1842,7 +1867,8 @@ class NormalActionsTest(BaseAction):
(None, -1),
):
events = self.verify_action(
- lambda: do_set_realm_signup_notifications_stream(
+ partial(
+ do_set_realm_signup_notifications_stream,
self.user_profile.realm,
signup_notifications_stream,
signup_notifications_stream_id,
@@ -1871,7 +1897,7 @@ class NormalActionsTest(BaseAction):
num_events = 5
events = self.verify_action(
- lambda: do_change_user_role(self.user_profile, role, acting_user=None),
+ partial(do_change_user_role, self.user_profile, role, acting_user=None),
num_events=num_events,
)
check_realm_user_update("events[0]", events[0], "role")
@@ -1919,7 +1945,7 @@ class NormalActionsTest(BaseAction):
else:
num_events = 5
events = self.verify_action(
- lambda: do_change_user_role(self.user_profile, role, acting_user=None),
+ partial(do_change_user_role, self.user_profile, role, acting_user=None),
num_events=num_events,
)
check_realm_user_update("events[0]", events[0], "role")
@@ -1947,7 +1973,7 @@ class NormalActionsTest(BaseAction):
do_change_user_role(self.user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
for role in [UserProfile.ROLE_MODERATOR, UserProfile.ROLE_MEMBER]:
events = self.verify_action(
- lambda: do_change_user_role(self.user_profile, role, acting_user=None),
+ partial(do_change_user_role, self.user_profile, role, acting_user=None),
num_events=4,
)
check_realm_user_update("events[0]", events[0], "role")
@@ -1982,7 +2008,7 @@ class NormalActionsTest(BaseAction):
else:
num_events = 5
events = self.verify_action(
- lambda: do_change_user_role(self.user_profile, role, acting_user=None),
+ partial(do_change_user_role, self.user_profile, role, acting_user=None),
num_events=num_events,
)
check_realm_user_update("events[0]", events[0], "role")
@@ -2028,7 +2054,8 @@ class NormalActionsTest(BaseAction):
for setting_value in [True, False]:
events = self.verify_action(
- lambda: do_change_user_setting(
+ partial(
+ do_change_user_setting,
self.user_profile,
notification_setting,
setting_value,
@@ -2042,7 +2069,8 @@ class NormalActionsTest(BaseAction):
# Also test with notification_settings_null=True
events = self.verify_action(
- lambda: do_change_user_setting(
+ partial(
+ do_change_user_setting,
self.user_profile,
notification_setting,
setting_value,
@@ -2070,8 +2098,12 @@ class NormalActionsTest(BaseAction):
for val in [True, False]:
events = self.verify_action(
- lambda: do_change_user_setting(
- self.user_profile, presence_enabled_setting, val, acting_user=self.user_profile
+ partial(
+ do_change_user_setting,
+ self.user_profile,
+ presence_enabled_setting,
+ val,
+ acting_user=self.user_profile,
),
num_events=3,
)
@@ -2545,7 +2577,7 @@ class NormalActionsTest(BaseAction):
stream = self.make_stream(old_name)
self.subscribe(self.user_profile, stream.name)
- action = lambda: do_rename_stream(stream, new_name, self.user_profile)
+ action = partial(do_rename_stream, stream, new_name, self.user_profile)
events = self.verify_action(action, num_events=3, include_streams=include_streams)
check_stream_update("events[0]", events[0])
@@ -2574,14 +2606,14 @@ class NormalActionsTest(BaseAction):
def test_deactivate_stream_neversubscribed(self) -> None:
for i, include_streams in enumerate([True, False]):
stream = self.make_stream(f"stream{i}")
- action = lambda: do_deactivate_stream(stream, acting_user=None)
+ action = partial(do_deactivate_stream, stream, acting_user=None)
events = self.verify_action(action, include_streams=include_streams)
check_stream_delete("events[0]", events[0])
self.assertIsNone(events[0]["streams"][0]["stream_weekly_traffic"])
def test_subscribe_other_user_never_subscribed(self) -> None:
for i, include_streams in enumerate([True, False]):
- action = lambda: self.subscribe(self.example_user("othello"), f"test_stream{i}")
+ action = partial(self.subscribe, self.example_user("othello"), f"test_stream{i}")
events = self.verify_action(action, num_events=2, include_streams=True)
check_subscription_peer_add("events[1]", events[1])
@@ -2938,8 +2970,12 @@ class RealmPropertyActionTest(BaseAction):
num_events = 1
events = self.verify_action(
- lambda: do_set_realm_property(
- self.user_profile.realm, name, val, acting_user=self.user_profile
+ partial(
+ do_set_realm_property,
+ self.user_profile.realm,
+ name,
+ val,
+ acting_user=self.user_profile,
),
state_change_expected=state_change_expected,
num_events=num_events,
@@ -3009,7 +3045,8 @@ class RealmPropertyActionTest(BaseAction):
new_group_id = user_group.id
events = self.verify_action(
- lambda: do_change_realm_permission_group_setting(
+ partial(
+ do_change_realm_permission_group_setting,
self.user_profile.realm,
setting_name,
user_group,
@@ -3089,8 +3126,12 @@ class RealmPropertyActionTest(BaseAction):
now = timezone_now()
state_change_expected = True
events = self.verify_action(
- lambda: do_set_realm_user_default_setting(
- realm_user_default, name, val, acting_user=self.user_profile
+ partial(
+ do_set_realm_user_default_setting,
+ realm_user_default,
+ name,
+ val,
+ acting_user=self.user_profile,
),
state_change_expected=state_change_expected,
)
@@ -3174,8 +3215,12 @@ class UserDisplayActionTest(BaseAction):
num_events = 3
events = self.verify_action(
- lambda: do_change_user_setting(
- self.user_profile, setting_name, value, acting_user=self.user_profile
+ partial(
+ do_change_user_setting,
+ self.user_profile,
+ setting_name,
+ value,
+ acting_user=self.user_profile,
),
num_events=num_events,
user_settings_object=user_settings_object,
@@ -3201,8 +3246,12 @@ class UserDisplayActionTest(BaseAction):
for value in values:
events = self.verify_action(
- lambda: do_change_user_setting(
- self.user_profile, "timezone", value, acting_user=self.user_profile
+ partial(
+ do_change_user_setting,
+ self.user_profile,
+ "timezone",
+ value,
+ acting_user=self.user_profile,
),
num_events=num_events,
)
diff --git a/zerver/tests/test_invite.py b/zerver/tests/test_invite.py
index e415a2b00b..cfdbb33a8f 100644
--- a/zerver/tests/test_invite.py
+++ b/zerver/tests/test_invite.py
@@ -14,6 +14,7 @@ from django.http import HttpRequest
from django.test import override_settings
from django.urls import reverse
from django.utils.timezone import now as timezone_now
+from returns.curry import partial
from confirmation import settings as confirmation_settings
from confirmation.models import (
@@ -1116,7 +1117,7 @@ so we didn't send them an invitation. We did send invitations to everyone else!"
for email in existing:
self.assertRaises(
PreregistrationUser.DoesNotExist,
- lambda: PreregistrationUser.objects.get(email=email),
+ partial(PreregistrationUser.objects.get, email=email),
)
for email in new:
self.assertTrue(PreregistrationUser.objects.get(email=email))
diff --git a/zerver/tests/test_upload.py b/zerver/tests/test_upload.py
index 86e35df3bb..9bc1d9c26c 100644
--- a/zerver/tests/test_upload.py
+++ b/zerver/tests/test_upload.py
@@ -1350,20 +1350,20 @@ class EmojiTest(UploadSerializeMixin, ZulipTestCase):
with self.assertRaises(BadImageError):
resize_emoji(corrupted_img_data)
+ def test_resize(size: int = 50) -> None:
+ resized_img_data, is_animated, still_img_data = resize_emoji(
+ animated_large_img_data, size=50
+ )
+ im = Image.open(io.BytesIO(resized_img_data))
+ self.assertEqual((size, size), im.size)
+ self.assertTrue(is_animated)
+ assert still_img_data
+ still_image = Image.open(io.BytesIO(still_img_data))
+ self.assertEqual((50, 50), still_image.size)
+
for img_format in ("gif", "png"):
animated_large_img_data = read_test_image_file(f"animated_large_img.{img_format}")
- def test_resize(size: int = 50) -> None:
- resized_img_data, is_animated, still_img_data = resize_emoji(
- animated_large_img_data, size=50
- )
- im = Image.open(io.BytesIO(resized_img_data))
- self.assertEqual((size, size), im.size)
- self.assertTrue(is_animated)
- assert still_img_data
- still_image = Image.open(io.BytesIO(still_img_data))
- self.assertEqual((50, 50), still_image.size)
-
# Test an image larger than max is resized
with patch("zerver.lib.upload.base.MAX_EMOJI_GIF_SIZE", 128):
test_resize()
diff --git a/zerver/tornado/django_api.py b/zerver/tornado/django_api.py
index 29b025debd..f092877042 100644
--- a/zerver/tornado/django_api.py
+++ b/zerver/tornado/django_api.py
@@ -9,6 +9,7 @@ from django.conf import settings
from django.db import transaction
from requests.adapters import ConnectionError, HTTPAdapter
from requests.models import PreparedRequest, Response
+from returns.curry import partial
from urllib3.util import Retry
from zerver.lib.queue import queue_json_publish
@@ -185,7 +186,7 @@ def send_event(
queue_json_publish(
notify_tornado_queue_name(port),
dict(event=event, users=port_users),
- lambda *args, **kwargs: send_notification_http(port, *args, **kwargs),
+ partial(send_notification_http, port),
)
diff --git a/zilencer/management/commands/queue_rate.py b/zilencer/management/commands/queue_rate.py
index 471bb09407..6377c4ce2b 100644
--- a/zilencer/management/commands/queue_rate.py
+++ b/zilencer/management/commands/queue_rate.py
@@ -70,10 +70,7 @@ class Command(BaseCommand):
lambda: queue_json_publish(queue_name, {}),
number=count,
)
- duration = timeit(
- lambda: worker.start(),
- number=1,
- )
+ duration = timeit(worker.start, number=1)
print(f" {i}/{reps}: {count}/{duration}s = {count / duration}/s")
total_time += duration
writer.writerow(