mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
zerver/lib: Use Python 3 syntax for typing for several files.
This adds a number of annotations that had been missed in previous passes.
This commit is contained in:
@@ -2551,8 +2551,8 @@ def do_change_full_name(user_profile, full_name, acting_user):
|
|||||||
send_event(dict(type='realm_bot', op='update', bot=payload),
|
send_event(dict(type='realm_bot', op='update', bot=payload),
|
||||||
bot_owner_user_ids(user_profile))
|
bot_owner_user_ids(user_profile))
|
||||||
|
|
||||||
def check_change_full_name(user_profile, full_name_raw, acting_user):
|
def check_change_full_name(user_profile: UserProfile, full_name_raw: Text,
|
||||||
# type: (UserProfile, Text, UserProfile) -> Text
|
acting_user: UserProfile) -> Text:
|
||||||
"""Verifies that the user's proposed full name is valid. The caller
|
"""Verifies that the user's proposed full name is valid. The caller
|
||||||
is responsible for checking check permissions. Returns the new
|
is responsible for checking check permissions. Returns the new
|
||||||
full name, which may differ from what was passed in (because this
|
full name, which may differ from what was passed in (because this
|
||||||
@@ -4382,8 +4382,8 @@ def do_send_create_user_group_event(user_group: UserGroup, members: List[UserPro
|
|||||||
)
|
)
|
||||||
send_event(event, active_user_ids(user_group.realm_id))
|
send_event(event, active_user_ids(user_group.realm_id))
|
||||||
|
|
||||||
def check_add_user_group(realm, name, initial_members, description):
|
def check_add_user_group(realm: Realm, name: Text, initial_members: List[UserProfile],
|
||||||
# type: (Realm, Text, List[UserProfile], Text) -> None
|
description: Text) -> None:
|
||||||
try:
|
try:
|
||||||
user_group = create_user_group(name, initial_members, realm, description=description)
|
user_group = create_user_group(name, initial_members, realm, description=description)
|
||||||
do_send_create_user_group_event(user_group, initial_members)
|
do_send_create_user_group_event(user_group, initial_members)
|
||||||
@@ -4394,14 +4394,12 @@ def do_send_user_group_update_event(user_group: UserGroup, data: Dict[str, Any])
|
|||||||
event = dict(type="user_group", op='update', group_id=user_group.id, data=data)
|
event = dict(type="user_group", op='update', group_id=user_group.id, data=data)
|
||||||
send_event(event, active_user_ids(user_group.realm_id))
|
send_event(event, active_user_ids(user_group.realm_id))
|
||||||
|
|
||||||
def do_update_user_group_name(user_group, name):
|
def do_update_user_group_name(user_group: UserGroup, name: Text) -> None:
|
||||||
# type: (UserGroup, Text) -> None
|
|
||||||
user_group.name = name
|
user_group.name = name
|
||||||
user_group.save(update_fields=['name'])
|
user_group.save(update_fields=['name'])
|
||||||
do_send_user_group_update_event(user_group, dict(name=name))
|
do_send_user_group_update_event(user_group, dict(name=name))
|
||||||
|
|
||||||
def do_update_user_group_description(user_group, description):
|
def do_update_user_group_description(user_group: UserGroup, description: Text) -> None:
|
||||||
# type: (UserGroup, Text) -> None
|
|
||||||
user_group.description = description
|
user_group.description = description
|
||||||
user_group.save(update_fields=['description'])
|
user_group.save(update_fields=['description'])
|
||||||
do_send_user_group_update_event(user_group, dict(description=description))
|
do_send_user_group_update_event(user_group, dict(description=description))
|
||||||
@@ -4415,8 +4413,7 @@ def do_send_user_group_members_update_event(event_name: Text,
|
|||||||
user_ids=user_ids)
|
user_ids=user_ids)
|
||||||
send_event(event, active_user_ids(user_group.realm_id))
|
send_event(event, active_user_ids(user_group.realm_id))
|
||||||
|
|
||||||
def bulk_add_members_to_user_group(user_group, user_profiles):
|
def bulk_add_members_to_user_group(user_group: UserGroup, user_profiles: List[UserProfile]) -> None:
|
||||||
# type: (UserGroup, List[UserProfile]) -> None
|
|
||||||
memberships = [UserGroupMembership(user_group_id=user_group.id,
|
memberships = [UserGroupMembership(user_group_id=user_group.id,
|
||||||
user_profile=user_profile)
|
user_profile=user_profile)
|
||||||
for user_profile in user_profiles]
|
for user_profile in user_profiles]
|
||||||
@@ -4425,8 +4422,7 @@ def bulk_add_members_to_user_group(user_group, user_profiles):
|
|||||||
user_ids = [up.id for up in user_profiles]
|
user_ids = [up.id for up in user_profiles]
|
||||||
do_send_user_group_members_update_event('add_members', user_group, user_ids)
|
do_send_user_group_members_update_event('add_members', user_group, user_ids)
|
||||||
|
|
||||||
def remove_members_from_user_group(user_group, user_profiles):
|
def remove_members_from_user_group(user_group: UserGroup, user_profiles: List[UserProfile]) -> None:
|
||||||
# type: (UserGroup, List[UserProfile]) -> None
|
|
||||||
UserGroupMembership.objects.filter(
|
UserGroupMembership.objects.filter(
|
||||||
user_group_id=user_group.id,
|
user_group_id=user_group.id,
|
||||||
user_profile__in=user_profiles).delete()
|
user_profile__in=user_profiles).delete()
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ from typing import Text
|
|||||||
|
|
||||||
from zerver.lib.utils import make_safe_digest
|
from zerver.lib.utils import make_safe_digest
|
||||||
|
|
||||||
if False:
|
from zerver.models import UserProfile
|
||||||
# Typing import inside `if False` to avoid import loop.
|
|
||||||
from zerver.models import UserProfile
|
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
@@ -30,8 +28,7 @@ def user_avatar_hash(uid: Text) -> Text:
|
|||||||
user_key = uid + settings.AVATAR_SALT
|
user_key = uid + settings.AVATAR_SALT
|
||||||
return make_safe_digest(user_key, hashlib.sha1)
|
return make_safe_digest(user_key, hashlib.sha1)
|
||||||
|
|
||||||
def user_avatar_path(user_profile):
|
def user_avatar_path(user_profile: UserProfile) -> Text:
|
||||||
# type: (UserProfile) -> Text
|
|
||||||
|
|
||||||
# WARNING: If this method is changed, you may need to do a migration
|
# WARNING: If this method is changed, you may need to do a migration
|
||||||
# similar to zerver/migrations/0060_move_avatars_to_be_uid_based.py .
|
# similar to zerver/migrations/0060_move_avatars_to_be_uid_based.py .
|
||||||
|
|||||||
@@ -9,13 +9,11 @@ from typing import Text, Dict, Optional
|
|||||||
class ConfigError(Exception):
|
class ConfigError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_bot_config(bot_profile):
|
def get_bot_config(bot_profile: UserProfile) -> Dict[Text, Text]:
|
||||||
# type: (UserProfile) -> Dict[Text, Text]
|
|
||||||
entries = BotUserConfigData.objects.filter(bot_profile=bot_profile)
|
entries = BotUserConfigData.objects.filter(bot_profile=bot_profile)
|
||||||
return {entry.key: entry.value for entry in entries}
|
return {entry.key: entry.value for entry in entries}
|
||||||
|
|
||||||
def get_bot_config_size(bot_profile, key=None):
|
def get_bot_config_size(bot_profile: UserProfile, key: Optional[Text]=None) -> int:
|
||||||
# type: (UserProfile, Optional[Text]) -> int
|
|
||||||
if key is None:
|
if key is None:
|
||||||
return BotUserConfigData.objects.filter(bot_profile=bot_profile) \
|
return BotUserConfigData.objects.filter(bot_profile=bot_profile) \
|
||||||
.annotate(key_size=Length('key'), value_size=Length('value')) \
|
.annotate(key_size=Length('key'), value_size=Length('value')) \
|
||||||
@@ -26,8 +24,7 @@ def get_bot_config_size(bot_profile, key=None):
|
|||||||
except BotUserConfigData.DoesNotExist:
|
except BotUserConfigData.DoesNotExist:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def set_bot_config(bot_profile, key, value):
|
def set_bot_config(bot_profile: UserProfile, key: Text, value: Text) -> None:
|
||||||
# type: (UserProfile, Text, Text) -> None
|
|
||||||
config_size_limit = settings.BOT_CONFIG_SIZE_LIMIT
|
config_size_limit = settings.BOT_CONFIG_SIZE_LIMIT
|
||||||
old_entry_size = get_bot_config_size(bot_profile, key)
|
old_entry_size = get_bot_config_size(bot_profile, key)
|
||||||
new_entry_size = len(key) + len(value)
|
new_entry_size = len(key) + len(value)
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ def get_bot_storage_size(bot_profile, key=None):
|
|||||||
except BotStorageData.DoesNotExist:
|
except BotStorageData.DoesNotExist:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def set_bot_storage(bot_profile, entries):
|
def set_bot_storage(bot_profile: UserProfile, entries: List[Tuple[str, str]]) -> None:
|
||||||
# type: (UserProfile, List[Tuple[str, str]]) -> None
|
|
||||||
storage_size_limit = settings.USER_STATE_SIZE_LIMIT
|
storage_size_limit = settings.USER_STATE_SIZE_LIMIT
|
||||||
storage_size_difference = 0
|
storage_size_difference = 0
|
||||||
for key, value in entries:
|
for key, value in entries:
|
||||||
@@ -47,17 +46,14 @@ def set_bot_storage(bot_profile, entries):
|
|||||||
BotStorageData.objects.update_or_create(bot_profile=bot_profile, key=key,
|
BotStorageData.objects.update_or_create(bot_profile=bot_profile, key=key,
|
||||||
defaults={'value': value})
|
defaults={'value': value})
|
||||||
|
|
||||||
def remove_bot_storage(bot_profile, keys):
|
def remove_bot_storage(bot_profile: UserProfile, keys: List[Text]) -> None:
|
||||||
# type: (UserProfile, List[Text]) -> None
|
|
||||||
queryset = BotStorageData.objects.filter(bot_profile=bot_profile, key__in=keys)
|
queryset = BotStorageData.objects.filter(bot_profile=bot_profile, key__in=keys)
|
||||||
if len(queryset) < len(keys):
|
if len(queryset) < len(keys):
|
||||||
raise StateError("Key does not exist.")
|
raise StateError("Key does not exist.")
|
||||||
queryset.delete()
|
queryset.delete()
|
||||||
|
|
||||||
def is_key_in_bot_storage(bot_profile, key):
|
def is_key_in_bot_storage(bot_profile: UserProfile, key: Text) -> bool:
|
||||||
# type: (UserProfile, Text) -> bool
|
|
||||||
return BotStorageData.objects.filter(bot_profile=bot_profile, key=key).exists()
|
return BotStorageData.objects.filter(bot_profile=bot_profile, key=key).exists()
|
||||||
|
|
||||||
def get_keys_in_bot_storage(bot_profile):
|
def get_keys_in_bot_storage(bot_profile: UserProfile) -> List[Text]:
|
||||||
# type: (UserProfile) -> List[Text]
|
|
||||||
return list(BotStorageData.objects.filter(bot_profile=bot_profile).values_list('key', flat=True))
|
return list(BotStorageData.objects.filter(bot_profile=bot_profile).values_list('key', flat=True))
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import os
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from zerver.models import UserProfile, Stream, Realm, Message
|
from zerver.models import UserProfile, Realm, Message
|
||||||
# These modules have to be imported for type annotations but
|
# These modules have to be imported for type annotations but
|
||||||
# they cannot be imported at runtime due to cyclic dependency.
|
# they cannot be imported at runtime due to cyclic dependency.
|
||||||
|
|
||||||
|
|||||||
@@ -535,8 +535,7 @@ def handle_push_notification(user_profile_id, missed_message):
|
|||||||
apns_payload,
|
apns_payload,
|
||||||
gcm_payload)
|
gcm_payload)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
def failure_processor(event):
|
def failure_processor(event: Dict[str, Any]) -> None:
|
||||||
# type: (Dict[str, Any]) -> None
|
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Maximum retries exceeded for trigger:%s event:push_notification" % (
|
"Maximum retries exceeded for trigger:%s event:push_notification" % (
|
||||||
event['user_profile_id']))
|
event['user_profile_id']))
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ from datetime import datetime, timedelta
|
|||||||
|
|
||||||
# Return the amount of Zulip usage for this user between the two
|
# Return the amount of Zulip usage for this user between the two
|
||||||
# given dates
|
# given dates
|
||||||
def seconds_usage_between(user_profile, begin, end):
|
def seconds_usage_between(user_profile: UserProfile, begin: datetime, end: datetime) -> timedelta:
|
||||||
# type: (UserProfile, datetime, datetime) -> timedelta
|
|
||||||
intervals = UserActivityInterval.objects.filter(user_profile=user_profile,
|
intervals = UserActivityInterval.objects.filter(user_profile=user_profile,
|
||||||
end__gte=begin,
|
end__gte=begin,
|
||||||
start__lte=end)
|
start__lte=end)
|
||||||
|
|||||||
@@ -59,8 +59,7 @@ from contextlib import contextmanager
|
|||||||
|
|
||||||
API_KEYS = {} # type: Dict[Text, Text]
|
API_KEYS = {} # type: Dict[Text, Text]
|
||||||
|
|
||||||
def flush_caches_for_testing():
|
def flush_caches_for_testing() -> None:
|
||||||
# type: () -> None
|
|
||||||
global API_KEYS
|
global API_KEYS
|
||||||
API_KEYS = {}
|
API_KEYS = {}
|
||||||
|
|
||||||
@@ -75,8 +74,7 @@ class UploadSerializeMixin(SerializeMixin):
|
|||||||
lockfile = 'var/upload_lock'
|
lockfile = 'var/upload_lock'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls, *args, **kwargs):
|
def setUpClass(cls: Any, *args: Any, **kwargs: Any) -> None:
|
||||||
# type: (*Any, **Any) -> None
|
|
||||||
if not os.path.exists(cls.lockfile):
|
if not os.path.exists(cls.lockfile):
|
||||||
with open(cls.lockfile, 'w'): # nocoverage - rare locking case
|
with open(cls.lockfile, 'w'): # nocoverage - rare locking case
|
||||||
pass
|
pass
|
||||||
@@ -102,8 +100,7 @@ class ZulipTestCase(TestCase):
|
|||||||
DEFAULT_SUBDOMAIN = "zulip"
|
DEFAULT_SUBDOMAIN = "zulip"
|
||||||
DEFAULT_REALM = Realm.objects.get(string_id='zulip')
|
DEFAULT_REALM = Realm.objects.get(string_id='zulip')
|
||||||
|
|
||||||
def set_http_host(self, kwargs):
|
def set_http_host(self, kwargs: Dict[str, Any]) -> None:
|
||||||
# type: (Dict[str, Any]) -> None
|
|
||||||
if 'subdomain' in kwargs:
|
if 'subdomain' in kwargs:
|
||||||
kwargs['HTTP_HOST'] = Realm.host_for_subdomain(kwargs['subdomain'])
|
kwargs['HTTP_HOST'] = Realm.host_for_subdomain(kwargs['subdomain'])
|
||||||
del kwargs['subdomain']
|
del kwargs['subdomain']
|
||||||
@@ -111,8 +108,7 @@ class ZulipTestCase(TestCase):
|
|||||||
kwargs['HTTP_HOST'] = Realm.host_for_subdomain(self.DEFAULT_SUBDOMAIN)
|
kwargs['HTTP_HOST'] = Realm.host_for_subdomain(self.DEFAULT_SUBDOMAIN)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_patch(self, url, info={}, **kwargs):
|
def client_patch(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
"""
|
"""
|
||||||
We need to urlencode, since Django's function won't do it for us.
|
We need to urlencode, since Django's function won't do it for us.
|
||||||
"""
|
"""
|
||||||
@@ -142,47 +138,41 @@ class ZulipTestCase(TestCase):
|
|||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_put(self, url, info={}, **kwargs):
|
def client_put(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
encoded = urllib.parse.urlencode(info)
|
encoded = urllib.parse.urlencode(info)
|
||||||
django_client = self.client # see WRAPPER_COMMENT
|
django_client = self.client # see WRAPPER_COMMENT
|
||||||
self.set_http_host(kwargs)
|
self.set_http_host(kwargs)
|
||||||
return django_client.put(url, encoded, **kwargs)
|
return django_client.put(url, encoded, **kwargs)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_delete(self, url, info={}, **kwargs):
|
def client_delete(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
encoded = urllib.parse.urlencode(info)
|
encoded = urllib.parse.urlencode(info)
|
||||||
django_client = self.client # see WRAPPER_COMMENT
|
django_client = self.client # see WRAPPER_COMMENT
|
||||||
self.set_http_host(kwargs)
|
self.set_http_host(kwargs)
|
||||||
return django_client.delete(url, encoded, **kwargs)
|
return django_client.delete(url, encoded, **kwargs)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_options(self, url, info={}, **kwargs):
|
def client_options(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
encoded = urllib.parse.urlencode(info)
|
encoded = urllib.parse.urlencode(info)
|
||||||
django_client = self.client # see WRAPPER_COMMENT
|
django_client = self.client # see WRAPPER_COMMENT
|
||||||
self.set_http_host(kwargs)
|
self.set_http_host(kwargs)
|
||||||
return django_client.options(url, encoded, **kwargs)
|
return django_client.options(url, encoded, **kwargs)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_head(self, url, info={}, **kwargs):
|
def client_head(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
encoded = urllib.parse.urlencode(info)
|
encoded = urllib.parse.urlencode(info)
|
||||||
django_client = self.client # see WRAPPER_COMMENT
|
django_client = self.client # see WRAPPER_COMMENT
|
||||||
self.set_http_host(kwargs)
|
self.set_http_host(kwargs)
|
||||||
return django_client.head(url, encoded, **kwargs)
|
return django_client.head(url, encoded, **kwargs)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_post(self, url, info={}, **kwargs):
|
def client_post(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
django_client = self.client # see WRAPPER_COMMENT
|
django_client = self.client # see WRAPPER_COMMENT
|
||||||
self.set_http_host(kwargs)
|
self.set_http_host(kwargs)
|
||||||
return django_client.post(url, info, **kwargs)
|
return django_client.post(url, info, **kwargs)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_post_request(self, url, req):
|
def client_post_request(self, url: Text, req: Any) -> HttpResponse:
|
||||||
# type: (Text, Any) -> HttpResponse
|
|
||||||
"""
|
"""
|
||||||
We simulate hitting an endpoint here, although we
|
We simulate hitting an endpoint here, although we
|
||||||
actually resolve the URL manually and hit the view
|
actually resolve the URL manually and hit the view
|
||||||
@@ -196,8 +186,7 @@ class ZulipTestCase(TestCase):
|
|||||||
return match.func(req)
|
return match.func(req)
|
||||||
|
|
||||||
@instrument_url
|
@instrument_url
|
||||||
def client_get(self, url, info={}, **kwargs):
|
def client_get(self, url: Text, info: Dict[str, Any]={}, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Dict[str, Any], **Any) -> HttpResponse
|
|
||||||
django_client = self.client # see WRAPPER_COMMENT
|
django_client = self.client # see WRAPPER_COMMENT
|
||||||
self.set_http_host(kwargs)
|
self.set_http_host(kwargs)
|
||||||
return django_client.get(url, info, **kwargs)
|
return django_client.get(url, info, **kwargs)
|
||||||
@@ -234,39 +223,32 @@ class ZulipTestCase(TestCase):
|
|||||||
me='me@zulip.com',
|
me='me@zulip.com',
|
||||||
)
|
)
|
||||||
|
|
||||||
def nonreg_user(self, name):
|
def nonreg_user(self, name: str) -> UserProfile:
|
||||||
# type: (str) -> UserProfile
|
|
||||||
email = self.nonreg_user_map[name]
|
email = self.nonreg_user_map[name]
|
||||||
return get_user(email, get_realm("zulip"))
|
return get_user(email, get_realm("zulip"))
|
||||||
|
|
||||||
def example_user(self, name):
|
def example_user(self, name: str) -> UserProfile:
|
||||||
# type: (str) -> UserProfile
|
|
||||||
email = self.example_user_map[name]
|
email = self.example_user_map[name]
|
||||||
return get_user(email, get_realm('zulip'))
|
return get_user(email, get_realm('zulip'))
|
||||||
|
|
||||||
def mit_user(self, name):
|
def mit_user(self, name: str) -> UserProfile:
|
||||||
# type: (str) -> UserProfile
|
|
||||||
email = self.mit_user_map[name]
|
email = self.mit_user_map[name]
|
||||||
return get_user(email, get_realm('zephyr'))
|
return get_user(email, get_realm('zephyr'))
|
||||||
|
|
||||||
def nonreg_email(self, name):
|
def nonreg_email(self, name: str) -> Text:
|
||||||
# type: (str) -> Text
|
|
||||||
return self.nonreg_user_map[name]
|
return self.nonreg_user_map[name]
|
||||||
|
|
||||||
def example_email(self, name):
|
def example_email(self, name: str) -> Text:
|
||||||
# type: (str) -> Text
|
|
||||||
return self.example_user_map[name]
|
return self.example_user_map[name]
|
||||||
|
|
||||||
def mit_email(self, name):
|
def mit_email(self, name: str) -> Text:
|
||||||
# type: (str) -> Text
|
|
||||||
return self.mit_user_map[name]
|
return self.mit_user_map[name]
|
||||||
|
|
||||||
def notification_bot(self):
|
def notification_bot(self) -> UserProfile:
|
||||||
# type: () -> UserProfile
|
|
||||||
return get_user('notification-bot@zulip.com', get_realm('zulip'))
|
return get_user('notification-bot@zulip.com', get_realm('zulip'))
|
||||||
|
|
||||||
def create_test_bot(self, email, user_profile, full_name, short_name, bot_type, service_name=None):
|
def create_test_bot(self, email: Text, user_profile: UserProfile, full_name: Text,
|
||||||
# type: (Text, UserProfile, Text, Text, int, str) -> UserProfile
|
short_name: Text, bot_type: int, service_name: str=None) -> UserProfile:
|
||||||
bot_profile = do_create_user(email=email, password='', realm=user_profile.realm,
|
bot_profile = do_create_user(email=email, password='', realm=user_profile.realm,
|
||||||
full_name=full_name, short_name=short_name,
|
full_name=full_name, short_name=short_name,
|
||||||
bot_type=bot_type, bot_owner=user_profile)
|
bot_type=bot_type, bot_owner=user_profile)
|
||||||
@@ -276,16 +258,16 @@ class ZulipTestCase(TestCase):
|
|||||||
token='abcdef')
|
token='abcdef')
|
||||||
return bot_profile
|
return bot_profile
|
||||||
|
|
||||||
def login_with_return(self, email, password=None, **kwargs):
|
def login_with_return(self, email: Text, password: Optional[Text]=None,
|
||||||
# type: (Text, Optional[Text], **Any) -> HttpResponse
|
**kwargs: Any) -> HttpResponse:
|
||||||
if password is None:
|
if password is None:
|
||||||
password = initial_password(email)
|
password = initial_password(email)
|
||||||
return self.client_post('/accounts/login/',
|
return self.client_post('/accounts/login/',
|
||||||
{'username': email, 'password': password},
|
{'username': email, 'password': password},
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def login(self, email, password=None, fails=False, realm=None):
|
def login(self, email: Text, password: Optional[Text]=None, fails: bool=False,
|
||||||
# type: (Text, Optional[Text], bool, Optional[Realm]) -> HttpResponse
|
realm: Optional[Realm]=None) -> HttpResponse:
|
||||||
if realm is None:
|
if realm is None:
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
if password is None:
|
if password is None:
|
||||||
@@ -297,21 +279,21 @@ class ZulipTestCase(TestCase):
|
|||||||
self.assertFalse(self.client.login(username=email, password=password,
|
self.assertFalse(self.client.login(username=email, password=password,
|
||||||
realm=realm))
|
realm=realm))
|
||||||
|
|
||||||
def logout(self):
|
def logout(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
||||||
def register(self, email, password, **kwargs):
|
def register(self, email: Text, password: Text, **kwargs: Any) -> HttpResponse:
|
||||||
# type: (Text, Text, **Any) -> HttpResponse
|
|
||||||
self.client_post('/accounts/home/', {'email': email},
|
self.client_post('/accounts/home/', {'email': email},
|
||||||
**kwargs)
|
**kwargs)
|
||||||
return self.submit_reg_form_for_user(email, password, **kwargs)
|
return self.submit_reg_form_for_user(email, password, **kwargs)
|
||||||
|
|
||||||
def submit_reg_form_for_user(self, email: Text, password: Text, realm_name: Optional[Text]="Zulip Test",
|
def submit_reg_form_for_user(
|
||||||
realm_subdomain: Optional[Text]="zuliptest",
|
self, email: Text, password: Text,
|
||||||
from_confirmation: Optional[Text]='', full_name: Optional[Text]=None,
|
realm_name: Optional[Text]="Zulip Test",
|
||||||
timezone: Optional[Text]='', realm_in_root_domain: Optional[Text]=None,
|
realm_subdomain: Optional[Text]="zuliptest",
|
||||||
default_stream_groups: Optional[List[Text]]=[], **kwargs: Any) -> HttpResponse:
|
from_confirmation: Optional[Text]='', full_name: Optional[Text]=None,
|
||||||
|
timezone: Optional[Text]='', realm_in_root_domain: Optional[Text]=None,
|
||||||
|
default_stream_groups: Optional[List[Text]]=[], **kwargs: Any) -> HttpResponse:
|
||||||
"""
|
"""
|
||||||
Stage two of the two-step registration process.
|
Stage two of the two-step registration process.
|
||||||
|
|
||||||
@@ -337,8 +319,8 @@ class ZulipTestCase(TestCase):
|
|||||||
payload['realm_in_root_domain'] = realm_in_root_domain
|
payload['realm_in_root_domain'] = realm_in_root_domain
|
||||||
return self.client_post('/accounts/register/', payload, **kwargs)
|
return self.client_post('/accounts/register/', payload, **kwargs)
|
||||||
|
|
||||||
def get_confirmation_url_from_outbox(self, email_address, *, url_pattern=None):
|
def get_confirmation_url_from_outbox(self, email_address: Text, *,
|
||||||
# type: (Text, Text) -> Text
|
url_pattern: Text=None) -> Text:
|
||||||
from django.core.mail import outbox
|
from django.core.mail import outbox
|
||||||
if url_pattern is None:
|
if url_pattern is None:
|
||||||
# This is a bit of a crude heuristic, but good enough for most tests.
|
# This is a bit of a crude heuristic, but good enough for most tests.
|
||||||
@@ -349,8 +331,7 @@ class ZulipTestCase(TestCase):
|
|||||||
else:
|
else:
|
||||||
raise AssertionError("Couldn't find a confirmation email.")
|
raise AssertionError("Couldn't find a confirmation email.")
|
||||||
|
|
||||||
def api_auth(self, identifier, realm="zulip"):
|
def api_auth(self, identifier: Text, realm: Text="zulip") -> Dict[str, Text]:
|
||||||
# type: (Text, Text) -> Dict[str, Text]
|
|
||||||
"""
|
"""
|
||||||
identifier: Can be an email or a remote server uuid.
|
identifier: Can be an email or a remote server uuid.
|
||||||
"""
|
"""
|
||||||
@@ -368,8 +349,7 @@ class ZulipTestCase(TestCase):
|
|||||||
'HTTP_AUTHORIZATION': 'Basic ' + base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
|
'HTTP_AUTHORIZATION': 'Basic ' + base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_streams(self, email, realm):
|
def get_streams(self, email: Text, realm: Realm) -> List[Text]:
|
||||||
# type: (Text, Realm) -> List[Text]
|
|
||||||
"""
|
"""
|
||||||
Helper function to get the stream names for a user
|
Helper function to get the stream names for a user
|
||||||
"""
|
"""
|
||||||
@@ -431,22 +411,19 @@ class ZulipTestCase(TestCase):
|
|||||||
data = result.json()
|
data = result.json()
|
||||||
return data['messages']
|
return data['messages']
|
||||||
|
|
||||||
def users_subscribed_to_stream(self, stream_name, realm):
|
def users_subscribed_to_stream(self, stream_name: Text, realm: Realm) -> List[UserProfile]:
|
||||||
# type: (Text, Realm) -> List[UserProfile]
|
|
||||||
stream = Stream.objects.get(name=stream_name, realm=realm)
|
stream = Stream.objects.get(name=stream_name, realm=realm)
|
||||||
recipient = Recipient.objects.get(type_id=stream.id, type=Recipient.STREAM)
|
recipient = Recipient.objects.get(type_id=stream.id, type=Recipient.STREAM)
|
||||||
subscriptions = Subscription.objects.filter(recipient=recipient, active=True)
|
subscriptions = Subscription.objects.filter(recipient=recipient, active=True)
|
||||||
|
|
||||||
return [subscription.user_profile for subscription in subscriptions]
|
return [subscription.user_profile for subscription in subscriptions]
|
||||||
|
|
||||||
def assert_url_serves_contents_of_file(self, url, result):
|
def assert_url_serves_contents_of_file(self, url: str, result: bytes) -> None:
|
||||||
# type: (str, bytes) -> None
|
|
||||||
response = self.client_get(url)
|
response = self.client_get(url)
|
||||||
data = b"".join(response.streaming_content)
|
data = b"".join(response.streaming_content)
|
||||||
self.assertEqual(result, data)
|
self.assertEqual(result, data)
|
||||||
|
|
||||||
def assert_json_success(self, result):
|
def assert_json_success(self, result: HttpResponse) -> Dict[str, Any]:
|
||||||
# type: (HttpResponse) -> Dict[str, Any]
|
|
||||||
"""
|
"""
|
||||||
Successful POSTs return a 200 and JSON of the form {"result": "success",
|
Successful POSTs return a 200 and JSON of the form {"result": "success",
|
||||||
"msg": ""}.
|
"msg": ""}.
|
||||||
@@ -463,8 +440,7 @@ class ZulipTestCase(TestCase):
|
|||||||
self.assertNotEqual(json["msg"], "Error parsing JSON in response!")
|
self.assertNotEqual(json["msg"], "Error parsing JSON in response!")
|
||||||
return json
|
return json
|
||||||
|
|
||||||
def get_json_error(self, result, status_code=400):
|
def get_json_error(self, result: HttpResponse, status_code: int=400) -> Dict[str, Any]:
|
||||||
# type: (HttpResponse, int) -> Dict[str, Any]
|
|
||||||
try:
|
try:
|
||||||
json = ujson.loads(result.content)
|
json = ujson.loads(result.content)
|
||||||
except Exception: # nocoverage
|
except Exception: # nocoverage
|
||||||
@@ -473,16 +449,14 @@ class ZulipTestCase(TestCase):
|
|||||||
self.assertEqual(json.get("result"), "error")
|
self.assertEqual(json.get("result"), "error")
|
||||||
return json['msg']
|
return json['msg']
|
||||||
|
|
||||||
def assert_json_error(self, result, msg, status_code=400):
|
def assert_json_error(self, result: HttpResponse, msg: Text, status_code: int=400) -> None:
|
||||||
# type: (HttpResponse, Text, int) -> None
|
|
||||||
"""
|
"""
|
||||||
Invalid POSTs return an error status code and JSON of the form
|
Invalid POSTs return an error status code and JSON of the form
|
||||||
{"result": "error", "msg": "reason"}.
|
{"result": "error", "msg": "reason"}.
|
||||||
"""
|
"""
|
||||||
self.assertEqual(self.get_json_error(result, status_code=status_code), msg)
|
self.assertEqual(self.get_json_error(result, status_code=status_code), msg)
|
||||||
|
|
||||||
def assert_length(self, items, count):
|
def assert_length(self, items: List[Any], count: int) -> None:
|
||||||
# type: (List[Any], int) -> None
|
|
||||||
actual_count = len(items)
|
actual_count = len(items)
|
||||||
if actual_count != count: # nocoverage
|
if actual_count != count: # nocoverage
|
||||||
print('ITEMS:\n')
|
print('ITEMS:\n')
|
||||||
@@ -491,38 +465,36 @@ class ZulipTestCase(TestCase):
|
|||||||
print("\nexpected length: %s\nactual length: %s" % (count, actual_count))
|
print("\nexpected length: %s\nactual length: %s" % (count, actual_count))
|
||||||
raise AssertionError('List is unexpected size!')
|
raise AssertionError('List is unexpected size!')
|
||||||
|
|
||||||
def assert_json_error_contains(self, result, msg_substring, status_code=400):
|
def assert_json_error_contains(self, result: HttpResponse, msg_substring: Text,
|
||||||
# type: (HttpResponse, Text, int) -> None
|
status_code: int=400) -> None:
|
||||||
self.assertIn(msg_substring, self.get_json_error(result, status_code=status_code))
|
self.assertIn(msg_substring, self.get_json_error(result, status_code=status_code))
|
||||||
|
|
||||||
def assert_in_response(self, substring, response):
|
def assert_in_response(self, substring: Text, response: HttpResponse) -> None:
|
||||||
# type: (Text, HttpResponse) -> None
|
|
||||||
self.assertIn(substring, response.content.decode('utf-8'))
|
self.assertIn(substring, response.content.decode('utf-8'))
|
||||||
|
|
||||||
def assert_in_success_response(self, substrings, response):
|
def assert_in_success_response(self, substrings: List[Text],
|
||||||
# type: (List[Text], HttpResponse) -> None
|
response: HttpResponse) -> None:
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
decoded = response.content.decode('utf-8')
|
decoded = response.content.decode('utf-8')
|
||||||
for substring in substrings:
|
for substring in substrings:
|
||||||
self.assertIn(substring, decoded)
|
self.assertIn(substring, decoded)
|
||||||
|
|
||||||
def assert_not_in_success_response(self, substrings, response):
|
def assert_not_in_success_response(self, substrings: List[Text],
|
||||||
# type: (List[Text], HttpResponse) -> None
|
response: HttpResponse) -> None:
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
decoded = response.content.decode('utf-8')
|
decoded = response.content.decode('utf-8')
|
||||||
for substring in substrings:
|
for substring in substrings:
|
||||||
self.assertNotIn(substring, decoded)
|
self.assertNotIn(substring, decoded)
|
||||||
|
|
||||||
def fixture_data(self, type, action, file_type='json'):
|
def fixture_data(self, type: Text, action: Text, file_type: Text='json') -> Text:
|
||||||
# type: (Text, Text, Text) -> Text
|
|
||||||
fn = os.path.join(
|
fn = os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
"../webhooks/%s/fixtures/%s.%s" % (type, action, file_type)
|
"../webhooks/%s/fixtures/%s.%s" % (type, action, file_type)
|
||||||
)
|
)
|
||||||
return open(fn).read()
|
return open(fn).read()
|
||||||
|
|
||||||
def make_stream(self, stream_name, realm=None, invite_only=False):
|
def make_stream(self, stream_name: Text, realm: Optional[Realm]=None,
|
||||||
# type: (Text, Optional[Realm], Optional[bool]) -> Stream
|
invite_only: Optional[bool]=False) -> Stream:
|
||||||
if realm is None:
|
if realm is None:
|
||||||
realm = self.DEFAULT_REALM
|
realm = self.DEFAULT_REALM
|
||||||
|
|
||||||
@@ -543,8 +515,7 @@ class ZulipTestCase(TestCase):
|
|||||||
return stream
|
return stream
|
||||||
|
|
||||||
# Subscribe to a stream directly
|
# Subscribe to a stream directly
|
||||||
def subscribe(self, user_profile, stream_name):
|
def subscribe(self, user_profile: UserProfile, stream_name: Text) -> Stream:
|
||||||
# type: (UserProfile, Text) -> Stream
|
|
||||||
try:
|
try:
|
||||||
stream = get_stream(stream_name, user_profile.realm)
|
stream = get_stream(stream_name, user_profile.realm)
|
||||||
from_stream_creation = False
|
from_stream_creation = False
|
||||||
@@ -553,8 +524,7 @@ class ZulipTestCase(TestCase):
|
|||||||
bulk_add_subscriptions([stream], [user_profile], from_stream_creation=from_stream_creation)
|
bulk_add_subscriptions([stream], [user_profile], from_stream_creation=from_stream_creation)
|
||||||
return stream
|
return stream
|
||||||
|
|
||||||
def unsubscribe(self, user_profile, stream_name):
|
def unsubscribe(self, user_profile: UserProfile, stream_name: Text) -> None:
|
||||||
# type: (UserProfile, Text) -> None
|
|
||||||
stream = get_stream(stream_name, user_profile.realm)
|
stream = get_stream(stream_name, user_profile.realm)
|
||||||
bulk_remove_subscriptions([user_profile], [stream])
|
bulk_remove_subscriptions([user_profile], [stream])
|
||||||
|
|
||||||
@@ -571,7 +541,8 @@ class ZulipTestCase(TestCase):
|
|||||||
**kw)
|
**kw)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def check_user_subscribed_only_to_streams(self, user_name: Text, streams: List[Stream]) -> None:
|
def check_user_subscribed_only_to_streams(self, user_name: Text,
|
||||||
|
streams: List[Stream]) -> None:
|
||||||
streams = sorted(streams, key=lambda x: x.name)
|
streams = sorted(streams, key=lambda x: x.name)
|
||||||
subscribed_streams = gather_subscriptions(self.nonreg_user(user_name))[0]
|
subscribed_streams = gather_subscriptions(self.nonreg_user(user_name))[0]
|
||||||
|
|
||||||
@@ -580,8 +551,9 @@ class ZulipTestCase(TestCase):
|
|||||||
for x, y in zip(subscribed_streams, streams):
|
for x, y in zip(subscribed_streams, streams):
|
||||||
self.assertEqual(x["name"], y.name)
|
self.assertEqual(x["name"], y.name)
|
||||||
|
|
||||||
def send_json_payload(self, user_profile, url, payload, stream_name=None, **post_params):
|
def send_json_payload(self, user_profile: UserProfile, url: Text,
|
||||||
# type: (UserProfile, Text, Union[Text, Dict[str, Any]], Optional[Text], **Any) -> Message
|
payload: Union[Text, Dict[str, Any]],
|
||||||
|
stream_name: Optional[Text]=None, **post_params: Any) -> Message:
|
||||||
if stream_name is not None:
|
if stream_name is not None:
|
||||||
self.subscribe(user_profile, stream_name)
|
self.subscribe(user_profile, stream_name)
|
||||||
|
|
||||||
@@ -597,17 +569,14 @@ class ZulipTestCase(TestCase):
|
|||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def get_last_message(self):
|
def get_last_message(self) -> Message:
|
||||||
# type: () -> Message
|
|
||||||
return Message.objects.latest('id')
|
return Message.objects.latest('id')
|
||||||
|
|
||||||
def get_second_to_last_message(self):
|
def get_second_to_last_message(self) -> Message:
|
||||||
# type: () -> Message
|
|
||||||
return Message.objects.all().order_by('-id')[1]
|
return Message.objects.all().order_by('-id')[1]
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def simulated_markdown_failure(self):
|
def simulated_markdown_failure(self) -> Iterator[None]:
|
||||||
# type: () -> Iterator[None]
|
|
||||||
'''
|
'''
|
||||||
This raises a failure inside of the try/except block of
|
This raises a failure inside of the try/except block of
|
||||||
bugdown.__init__.do_convert.
|
bugdown.__init__.do_convert.
|
||||||
@@ -632,12 +601,10 @@ class WebhookTestCase(ZulipTestCase):
|
|||||||
FIXTURE_DIR_NAME = None # type: Optional[Text]
|
FIXTURE_DIR_NAME = None # type: Optional[Text]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def test_user(self):
|
def test_user(self) -> UserProfile:
|
||||||
# type: () -> UserProfile
|
|
||||||
return get_user(self.TEST_USER_EMAIL, get_realm("zulip"))
|
return get_user(self.TEST_USER_EMAIL, get_realm("zulip"))
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
self.url = self.build_webhook_url()
|
self.url = self.build_webhook_url()
|
||||||
|
|
||||||
def send_and_test_stream_message(self, fixture_name, expected_subject=None,
|
def send_and_test_stream_message(self, fixture_name, expected_subject=None,
|
||||||
@@ -666,8 +633,7 @@ class WebhookTestCase(ZulipTestCase):
|
|||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def build_webhook_url(self, *args, **kwargs):
|
def build_webhook_url(self, *args: Any, **kwargs: Any) -> Text:
|
||||||
# type: (*Any, **Any) -> Text
|
|
||||||
url = self.URL_TEMPLATE
|
url = self.URL_TEMPLATE
|
||||||
if url.find("api_key") >= 0:
|
if url.find("api_key") >= 0:
|
||||||
api_key = self.test_user.api_key
|
api_key = self.test_user.api_key
|
||||||
@@ -690,18 +656,15 @@ class WebhookTestCase(ZulipTestCase):
|
|||||||
|
|
||||||
return url[:-1] if has_arguments else url
|
return url[:-1] if has_arguments else url
|
||||||
|
|
||||||
def get_body(self, fixture_name):
|
def get_body(self, fixture_name: Text) -> Union[Text, Dict[str, Text]]:
|
||||||
# type: (Text) -> Union[Text, Dict[str, Text]]
|
|
||||||
"""Can be implemented either as returning a dictionary containing the
|
"""Can be implemented either as returning a dictionary containing the
|
||||||
post parameters or as string containing the body of the request."""
|
post parameters or as string containing the body of the request."""
|
||||||
return ujson.dumps(ujson.loads(self.fixture_data(self.FIXTURE_DIR_NAME, fixture_name)))
|
return ujson.dumps(ujson.loads(self.fixture_data(self.FIXTURE_DIR_NAME, fixture_name)))
|
||||||
|
|
||||||
def do_test_subject(self, msg, expected_subject):
|
def do_test_subject(self, msg: Message, expected_subject: Optional[Text]) -> None:
|
||||||
# type: (Message, Optional[Text]) -> None
|
|
||||||
if expected_subject is not None:
|
if expected_subject is not None:
|
||||||
self.assertEqual(msg.topic_name(), expected_subject)
|
self.assertEqual(msg.topic_name(), expected_subject)
|
||||||
|
|
||||||
def do_test_message(self, msg, expected_message):
|
def do_test_message(self, msg: Message, expected_message: Optional[Text]) -> None:
|
||||||
# type: (Message, Optional[Text]) -> None
|
|
||||||
if expected_message is not None:
|
if expected_message is not None:
|
||||||
self.assertEqual(msg.content, expected_message)
|
self.assertEqual(msg.content, expected_message)
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ def create_user_group(name: Text, members: List[UserProfile], realm: Realm,
|
|||||||
])
|
])
|
||||||
return user_group
|
return user_group
|
||||||
|
|
||||||
def get_memberships_of_users(user_group, members):
|
def get_memberships_of_users(user_group: UserGroup, members: List[UserProfile]) -> List[int]:
|
||||||
# type: (UserGroup, List[UserProfile]) -> List[int]
|
|
||||||
return list(UserGroupMembership.objects.filter(
|
return list(UserGroupMembership.objects.filter(
|
||||||
user_group=user_group,
|
user_group=user_group,
|
||||||
user_profile__in=members).values_list('user_profile_id', flat=True))
|
user_profile__in=members).values_list('user_profile_id', flat=True))
|
||||||
|
|||||||
Reference in New Issue
Block a user