mypy: Convert several directories to use typing.Text.

Specifically, these directories are converted: [analytics/, scripts/,
tools/, zerver/management/, zilencer/, zproject/]
This commit is contained in:
anirudhjain75 2016-12-08 09:36:51 +05:30 committed by Tim Abbott
parent 2288120155
commit beaa62cafa
16 changed files with 82 additions and 95 deletions

View File

@ -8,8 +8,7 @@ from analytics.models import InstallationCount, RealmCount, \
from zerver.models import Realm, UserProfile, Message, Stream, models from zerver.models import Realm, UserProfile, Message, Stream, models
from zerver.lib.timestamp import floor_to_day from zerver.lib.timestamp import floor_to_day
from typing import Any, Optional, Type, Tuple from typing import Any, Optional, Type, Tuple, Text
from six import text_type
import logging import logging
import time import time
@ -37,7 +36,7 @@ class CountStat(object):
GAUGE = 'gauge' GAUGE = 'gauge'
def __init__(self, property, zerver_count_query, filter_args, group_by, frequency, is_gauge): def __init__(self, property, zerver_count_query, filter_args, group_by, frequency, is_gauge):
# type: (text_type, ZerverCountQuery, Dict[str, bool], Optional[Tuple[models.Model, str]], str, bool) -> None # type: (Text, ZerverCountQuery, Dict[str, bool], Optional[Tuple[models.Model, str]], str, bool) -> None
self.property = property self.property = property
self.zerver_count_query = zerver_count_query self.zerver_count_query = zerver_count_query
# might have to do something different for bitfields # might have to do something different for bitfields
@ -50,7 +49,7 @@ class CountStat(object):
class ZerverCountQuery(object): class ZerverCountQuery(object):
def __init__(self, zerver_table, analytics_table, query): def __init__(self, zerver_table, analytics_table, query):
# type: (Type[models.Model], Type[BaseCount], text_type) -> None # type: (Type[models.Model], Type[BaseCount], Text) -> None
self.zerver_table = zerver_table self.zerver_table = zerver_table
self.analytics_table = analytics_table self.analytics_table = analytics_table
self.query = query self.query = query

View File

@ -7,11 +7,10 @@ from zerver.lib.timestamp import datetime_to_UTC, floor_to_day
import datetime import datetime
from six import text_type from typing import Optional, Tuple, Union, Dict, Any, Text
from typing import Optional, Tuple, Union, Dict, Any
class FillState(ModelReprMixin, models.Model): class FillState(ModelReprMixin, models.Model):
property = models.CharField(max_length=40, unique=True) # type: text_type property = models.CharField(max_length=40, unique=True) # type: Text
end_time = models.DateTimeField() # type: datetime.datetime end_time = models.DateTimeField() # type: datetime.datetime
# Valid states are {DONE, STARTED} # Valid states are {DONE, STARTED}
@ -22,11 +21,11 @@ class FillState(ModelReprMixin, models.Model):
last_modified = models.DateTimeField(auto_now=True) # type: datetime.datetime last_modified = models.DateTimeField(auto_now=True) # type: datetime.datetime
def __unicode__(self): def __unicode__(self):
# type: () -> text_type # type: () -> Text
return u"<FillState: %s %s %s>" % (self.property, self.end_time, self.state) return u"<FillState: %s %s %s>" % (self.property, self.end_time, self.state)
def get_fill_state(property): def get_fill_state(property):
# type: (text_type) -> Optional[Dict[str, Any]] # type: (Text) -> Optional[Dict[str, Any]]
try: try:
return FillState.objects.filter(property = property).values('end_time', 'state')[0] return FillState.objects.filter(property = property).values('end_time', 'state')[0]
except IndexError: except IndexError:
@ -41,20 +40,20 @@ def installation_epoch():
# would only ever make entries here by hand # would only ever make entries here by hand
class Anomaly(ModelReprMixin, models.Model): class Anomaly(ModelReprMixin, models.Model):
info = models.CharField(max_length=1000) # type: text_type info = models.CharField(max_length=1000) # type: Text
def __unicode__(self): def __unicode__(self):
# type: () -> text_type # type: () -> Text
return u"<Anomaly: %s... %s>" % (self.info, self.id) return u"<Anomaly: %s... %s>" % (self.info, self.id)
class BaseCount(ModelReprMixin, models.Model): class BaseCount(ModelReprMixin, models.Model):
# Note: When inheriting from BaseCount, you may want to rearrange # Note: When inheriting from BaseCount, you may want to rearrange
# the order of the columns in the migration to make sure they # the order of the columns in the migration to make sure they
# match how you'd like the table to be arranged. # match how you'd like the table to be arranged.
property = models.CharField(max_length=32) # type: text_type property = models.CharField(max_length=32) # type: Text
subgroup = models.CharField(max_length=16, null=True) # type: text_type subgroup = models.CharField(max_length=16, null=True) # type: Text
end_time = models.DateTimeField() # type: datetime.datetime end_time = models.DateTimeField() # type: datetime.datetime
interval = models.CharField(max_length=8) # type: text_type interval = models.CharField(max_length=8) # type: Text
value = models.BigIntegerField() # type: int value = models.BigIntegerField() # type: int
anomaly = models.ForeignKey(Anomaly, null=True) # type: Optional[Anomaly] anomaly = models.ForeignKey(Anomaly, null=True) # type: Optional[Anomaly]
@ -87,7 +86,7 @@ class InstallationCount(BaseCount):
return None return None
def __unicode__(self): def __unicode__(self):
# type: () -> text_type # type: () -> Text
return u"<InstallationCount: %s %s>" % (self.property, self.value) return u"<InstallationCount: %s %s>" % (self.property, self.value)
class RealmCount(BaseCount): class RealmCount(BaseCount):
@ -107,7 +106,7 @@ class RealmCount(BaseCount):
return Realm return Realm
def __unicode__(self): def __unicode__(self):
# type: () -> text_type # type: () -> Text
return u"<RealmCount: %s %s %s>" % (self.realm, self.property, self.value) return u"<RealmCount: %s %s %s>" % (self.realm, self.property, self.value)
class UserCount(BaseCount): class UserCount(BaseCount):
@ -128,7 +127,7 @@ class UserCount(BaseCount):
return UserProfile return UserProfile
def __unicode__(self): def __unicode__(self):
# type: () -> text_type # type: () -> Text
return u"<UserCount: %s %s %s>" % (self.user, self.property, self.value) return u"<UserCount: %s %s %s>" % (self.user, self.property, self.value)
class StreamCount(BaseCount): class StreamCount(BaseCount):
@ -149,5 +148,5 @@ class StreamCount(BaseCount):
return Stream return Stream
def __unicode__(self): def __unicode__(self):
# type: () -> text_type # type: () -> Text
return u"<StreamCount: %s %s %s %s>" % (self.stream, self.property, self.value, self.id) return u"<StreamCount: %s %s %s %s>" % (self.stream, self.property, self.value, self.id)

View File

@ -14,8 +14,7 @@ from zerver.models import Realm, UserProfile, Message, Stream, Recipient, \
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any, Type, Optional from typing import Any, Type, Optional, Text
from six import text_type
class AnalyticsTestCase(TestCase): class AnalyticsTestCase(TestCase):
MINUTE = timedelta(seconds = 60) MINUTE = timedelta(seconds = 60)
@ -71,7 +70,7 @@ class AnalyticsTestCase(TestCase):
# kwargs should only ever be a UserProfile or Stream. # kwargs should only ever be a UserProfile or Stream.
def assertCountEquals(self, table, property, value, end_time = TIME_ZERO, interval = CountStat.HOUR, def assertCountEquals(self, table, property, value, end_time = TIME_ZERO, interval = CountStat.HOUR,
realm = None, **kwargs): realm = None, **kwargs):
# type: (Type[BaseCount], text_type, int, datetime, str, Optional[Realm], **models.Model) -> None # type: (Type[BaseCount], Text, int, datetime, str, Optional[Realm], **models.Model) -> None
if realm is None: if realm is None:
realm = self.default_realm realm = self.default_realm
self.assertEqual(table.objects.filter(realm=realm, self.assertEqual(table.objects.filter(realm=realm,
@ -134,7 +133,7 @@ class TestProcessCountStat(AnalyticsTestCase):
return count_stat return count_stat
def assertFillStateEquals(self, end_time, state = FillState.DONE, property = None): def assertFillStateEquals(self, end_time, state = FillState.DONE, property = None):
# type: (datetime, int, Optional[text_type]) -> None # type: (datetime, int, Optional[Text]) -> None
count_stat = self.make_dummy_count_stat(end_time) count_stat = self.make_dummy_count_stat(end_time)
if property is None: if property is None:
property = count_stat.property property = count_stat.property

View File

@ -1,7 +1,6 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
from six import text_type from typing import Any, Dict, List, Tuple, Optional, Sequence, Callable, Union, Text
from typing import Any, Dict, List, Tuple, Optional, Sequence, Callable, Union
from django.db import connection from django.db import connection
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
@ -789,7 +788,7 @@ def user_activity_summary_table(user_summary):
return make_table(title, cols, rows) return make_table(title, cols, rows)
def realm_user_summary_table(all_records, admin_emails): def realm_user_summary_table(all_records, admin_emails):
# type: (List[QuerySet], Set[text_type]) -> Tuple[Dict[str, Dict[str, Any]], str] # type: (List[QuerySet], Set[Text]) -> Tuple[Dict[str, Dict[str, Any]], str]
user_records = {} user_records = {}
def by_email(record): def by_email(record):

View File

@ -5,7 +5,7 @@ from __future__ import print_function
import sys, os, os.path import sys, os, os.path
from os.path import dirname, abspath from os.path import dirname, abspath
if False: if False:
from typing import Dict, Optional from typing import Dict, Optional, Text
BASE_DIR = dirname(dirname(dirname(abspath(__file__)))) BASE_DIR = dirname(dirname(dirname(abspath(__file__))))
sys.path.append(BASE_DIR) sys.path.append(BASE_DIR)
@ -14,7 +14,6 @@ import scripts.lib.setup_path_on_import
os.environ['DJANGO_SETTINGS_MODULE'] = 'zproject.settings' os.environ['DJANGO_SETTINGS_MODULE'] = 'zproject.settings'
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
from six import text_type
import six import six
import argparse import argparse
from zerver.lib.str_utils import force_str from zerver.lib.str_utils import force_str
@ -30,7 +29,7 @@ AUTOGENERATED_SETTINGS = ['shared_secret', 'avatar_salt', 'rabbitmq_password', '
# TODO: We can eliminate this function if we refactor the install # TODO: We can eliminate this function if we refactor the install
# script to run generate_secrets before zulip-puppet-apply. # script to run generate_secrets before zulip-puppet-apply.
def generate_camo_config_file(camo_key): def generate_camo_config_file(camo_key):
# type: (text_type) -> None # type: (Text) -> None
camo_config = """ENABLED=yes camo_config = """ENABLED=yes
PORT=9292 PORT=9292
CAMO_KEY=%s CAMO_KEY=%s
@ -40,13 +39,13 @@ CAMO_KEY=%s
print("Generated Camo config file %s" % (CAMO_CONFIG_FILENAME,)) print("Generated Camo config file %s" % (CAMO_CONFIG_FILENAME,))
def generate_django_secretkey(): def generate_django_secretkey():
# type: () -> text_type # type: () -> Text
"""Secret key generation taken from Django's startproject.py""" """Secret key generation taken from Django's startproject.py"""
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
return get_random_string(50, chars) return get_random_string(50, chars)
def get_old_conf(output_filename): def get_old_conf(output_filename):
# type: (text_type) -> Dict[str, text_type] # type: (Text) -> Dict[str, Text]
if not os.path.exists(output_filename): if not os.path.exists(output_filename):
return {} return {}
@ -54,7 +53,7 @@ def get_old_conf(output_filename):
secrets_file.read(output_filename) secrets_file.read(output_filename)
def get_secret(key): def get_secret(key):
# type: (text_type) -> Optional[text_type] # type: (Text) -> Optional[Text]
if secrets_file.has_option('secrets', key): if secrets_file.has_option('secrets', key):
return secrets_file.get('secrets', key) return secrets_file.get('secrets', key)
return None return None
@ -72,7 +71,7 @@ def generate_secrets(development=False):
lines = [u'[secrets]\n'] lines = [u'[secrets]\n']
def config_line(var, value): def config_line(var, value):
# type: (text_type, text_type) -> text_type # type: (Text, Text) -> Text
return "%s = %s\n" % (var, value) return "%s = %s\n" % (var, value)
old_conf = get_old_conf(OUTPUT_SETTINGS_FILENAME) old_conf = get_old_conf(OUTPUT_SETTINGS_FILENAME)

View File

@ -8,8 +8,8 @@ import json
import sys import sys
import hashlib import hashlib
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from six import unichr, text_type from six import unichr
from typing import Union from typing import Union, Text
from os.path import dirname from os.path import dirname
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
@ -40,7 +40,7 @@ class MissingGlyphError(Exception):
pass pass
def color_font(name, code_point, code_point_to_fname_map): def color_font(name, code_point, code_point_to_fname_map):
# type: (str, str, Dict[int, Union[text_type, bytes]]) -> None # type: (str, str, Dict[int, Union[Text, bytes]]) -> None
glyph_name = code_point_to_fname_map[int(code_point, 16)] glyph_name = code_point_to_fname_map[int(code_point, 16)]
in_name = 'bitmaps/strike0/{}.png'.format(glyph_name) in_name = 'bitmaps/strike0/{}.png'.format(glyph_name)
@ -75,11 +75,11 @@ def bw_font(name, code_point):
) )
def code_point_to_file_name_map(ttx): def code_point_to_file_name_map(ttx):
# type: (str) -> Dict[int, Union[text_type, bytes]] # type: (str) -> Dict[int, Union[Text, bytes]]
"""Given the NotoColorEmoji.ttx file, parse it to generate a map from """Given the NotoColorEmoji.ttx file, parse it to generate a map from
codepoint to filename (a la glyph0****.png) codepoint to filename (a la glyph0****.png)
""" """
result = {} # type: Dict[int, Union[text_type, bytes]] result = {} # type: Dict[int, Union[Text, bytes]]
xml = ET.parse(ttx) xml = ET.parse(ttx)
for elem in xml.find("*cmap_format_12"): for elem in xml.find("*cmap_format_12"):
code_point = int(elem.attrib["code"], 16) code_point = int(elem.attrib["code"], 16)

View File

@ -4,8 +4,7 @@ import os
import re import re
import ujson import ujson
from six import text_type from typing import Any, Dict, List, Text
from typing import Any, Dict, List
from django.core.management.commands import compilemessages from django.core.management.commands import compilemessages
from django.conf import settings from django.conf import settings
@ -20,12 +19,12 @@ class Command(compilemessages.Command):
self.extract_language_options() self.extract_language_options()
def get_po_filename(self, locale_path, locale): def get_po_filename(self, locale_path, locale):
# type: (text_type, text_type) -> text_type # type: (Text, Text) -> Text
po_template = '{}/{}/LC_MESSAGES/django.po' po_template = '{}/{}/LC_MESSAGES/django.po'
return po_template.format(locale_path, locale) return po_template.format(locale_path, locale)
def get_json_filename(self, locale_path, locale): def get_json_filename(self, locale_path, locale):
# type: (text_type, text_type) -> text_type # type: (Text, Text) -> Text
return "{}/{}/translations.json".format(locale_path, locale) return "{}/{}/translations.json".format(locale_path, locale)
def extract_language_options(self): def extract_language_options(self):
@ -81,7 +80,7 @@ class Command(compilemessages.Command):
ujson.dump(data, writer, indent=2) ujson.dump(data, writer, indent=2)
def get_translation_percentage(self, locale_path, locale): def get_translation_percentage(self, locale_path, locale):
# type: (text_type, text_type) -> int # type: (Text, Text) -> int
# backend stats # backend stats
po = polib.pofile(self.get_po_filename(locale_path, locale)) po = polib.pofile(self.get_po_filename(locale_path, locale))

View File

@ -1,7 +1,6 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import print_function from __future__ import print_function
from six import text_type
from typing import Any from typing import Any
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand

View File

@ -1,6 +1,6 @@
from __future__ import absolute_import from __future__ import absolute_import
from typing import Any, Iterable, Tuple from typing import Any, Iterable, Tuple, Text
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
@ -12,12 +12,11 @@ from zerver.lib.bulk_create import bulk_create_users
from zerver.lib.actions import set_default_streams, do_create_realm from zerver.lib.actions import set_default_streams, do_create_realm
from argparse import ArgumentParser from argparse import ArgumentParser
from six import text_type
settings.TORNADO_SERVER = None settings.TORNADO_SERVER = None
def create_users(name_list, bot_type=None): def create_users(name_list, bot_type=None):
# type: (Iterable[Tuple[text_type, text_type]], int) -> None # type: (Iterable[Tuple[Text, Text]], int) -> None
realms = {} realms = {}
for realm in Realm.objects.all(): for realm in Realm.objects.all():
realms[realm.domain] = realm realms[realm.domain] = realm

View File

@ -30,14 +30,13 @@ http://stackoverflow.com/questions/2090717/getting-translation-strings-for-jinja
""" """
from __future__ import absolute_import from __future__ import absolute_import
from typing import Any, Dict, Iterable, Optional, Mapping, Set, Tuple from typing import Any, Dict, Iterable, Optional, Mapping, Set, Tuple, Text
from argparse import ArgumentParser from argparse import ArgumentParser
import os import os
import re import re
import glob import glob
import json import json
from six import text_type
from six.moves import filter from six.moves import filter
from six.moves import map from six.moves import map
from six.moves import zip from six.moves import zip
@ -65,7 +64,7 @@ multiline_js_comment = re.compile("/\*.*?\*/", re.DOTALL)
singleline_js_comment = re.compile("//.*?\n") singleline_js_comment = re.compile("//.*?\n")
def strip_whitespaces(src): def strip_whitespaces(src):
# type: (text_type) -> text_type # type: (Text) -> Text
src = strip_whitespace_left.sub(u'\\1', src) src = strip_whitespace_left.sub(u'\\1', src)
src = strip_whitespace_right.sub(u'\\1', src) src = strip_whitespace_right.sub(u'\\1', src)
return src return src
@ -120,7 +119,7 @@ class Command(makemessages.Command):
trans_real.constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?')).*\)""") trans_real.constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?')).*\)""")
def my_templatize(src, origin=None): def my_templatize(src, origin=None):
# type: (text_type, Optional[text_type]) -> text_type # type: (Text, Optional[Text]) -> Text
new_src = strip_whitespaces(src) new_src = strip_whitespaces(src)
return old_templatize(new_src, origin) return old_templatize(new_src, origin)

View File

@ -19,15 +19,14 @@ from zilencer.models import Deployment
import random import random
import os import os
from optparse import make_option from optparse import make_option
from six import text_type
from six.moves import range from six.moves import range
from typing import Any, Callable, Dict, List, Iterable, Mapping, Sequence, Set, Tuple from typing import Any, Callable, Dict, List, Iterable, Mapping, Sequence, Set, Tuple, Text
settings.TORNADO_SERVER = None settings.TORNADO_SERVER = None
def create_users(realms, name_list, bot_type=None): def create_users(realms, name_list, bot_type=None):
# type: (Mapping[text_type, Realm], Iterable[Tuple[text_type, text_type]], int) -> None # type: (Mapping[Text, Realm], Iterable[Tuple[Text, Text]], int) -> None
user_set = set() # type: Set[Tuple[text_type, text_type, text_type, bool]] user_set = set() # type: Set[Tuple[Text, Text, Text, bool]]
for full_name, email in name_list: for full_name, email in name_list:
short_name = email_to_username(email) short_name = email_to_username(email)
user_set.add((email, full_name, short_name, True)) user_set.add((email, full_name, short_name, True))
@ -35,8 +34,8 @@ def create_users(realms, name_list, bot_type=None):
bulk_create_users(realms, user_set, bot_type=bot_type, tos_version=tos_version) bulk_create_users(realms, user_set, bot_type=bot_type, tos_version=tos_version)
def create_streams(realms, realm, stream_list): def create_streams(realms, realm, stream_list):
# type: (Mapping[text_type, Realm], Realm, Iterable[text_type]) -> None # type: (Mapping[Text, Realm], Realm, Iterable[Text]) -> None
stream_set = set() # type: Set[Tuple[text_type, text_type]] stream_set = set() # type: Set[Tuple[Text, Text]]
for stream_name in stream_list: for stream_name in stream_list:
stream_set.add((realm.domain, stream_name)) stream_set.add((realm.domain, stream_name))
bulk_create_streams(realms, stream_set) bulk_create_streams(realms, stream_set)
@ -127,7 +126,7 @@ class Command(BaseCommand):
string_id="mit", name="MIT", restricted_to_domain=True, string_id="mit", name="MIT", restricted_to_domain=True,
invite_required=False, org_type=Realm.CORPORATE, domain="mit.edu") invite_required=False, org_type=Realm.CORPORATE, domain="mit.edu")
RealmAlias.objects.create(realm=mit_realm, domain="mit.edu") RealmAlias.objects.create(realm=mit_realm, domain="mit.edu")
realms = {} # type: Dict[text_type, Realm] realms = {} # type: Dict[Text, Realm]
for realm in Realm.objects.all(): for realm in Realm.objects.all():
realms[realm.domain] = realm realms[realm.domain] = realm
@ -363,7 +362,7 @@ def send_messages(data):
# Pick a random subscriber to the stream # Pick a random subscriber to the stream
message.sender = random.choice(Subscription.objects.filter( message.sender = random.choice(Subscription.objects.filter(
recipient=message.recipient)).user_profile recipient=message.recipient)).user_profile
message.subject = stream.name + text_type(random.randint(1, 3)) message.subject = stream.name + Text(random.randint(1, 3))
saved_data['subject'] = message.subject saved_data['subject'] = message.subject
message.pub_date = now() message.pub_date = now()

View File

@ -1,11 +1,11 @@
from django.db import models from django.db import models
from django.db.models import Manager from django.db.models import Manager
from six import text_type from typing import Text
import zerver.models import zerver.models
def get_deployment_by_domain(domain): def get_deployment_by_domain(domain):
# type: (text_type) -> Deployment # type: (Text) -> Deployment
return Deployment.objects.get(realms__domain=domain) return Deployment.objects.get(realms__domain=domain)
class Deployment(models.Model): class Deployment(models.Model):
@ -15,19 +15,19 @@ class Deployment(models.Model):
# TODO: This should really become the public portion of a keypair, and # TODO: This should really become the public portion of a keypair, and
# it should be settable only with an initial bearer "activation key" # it should be settable only with an initial bearer "activation key"
api_key = models.CharField(max_length=32, null=True) # type: text_type api_key = models.CharField(max_length=32, null=True) # type: Text
base_api_url = models.CharField(max_length=128) # type: text_type base_api_url = models.CharField(max_length=128) # type: Text
base_site_url = models.CharField(max_length=128) # type: text_type base_site_url = models.CharField(max_length=128) # type: Text
@property @property
def endpoints(self): def endpoints(self):
# type: () -> Dict[str, text_type] # type: () -> Dict[str, Text]
return {'base_api_url': self.base_api_url, 'base_site_url': self.base_site_url} return {'base_api_url': self.base_api_url, 'base_site_url': self.base_site_url}
@property @property
def name(self): def name(self):
# type: () -> text_type # type: () -> Text
# TODO: This only does the right thing for prod because prod authenticates to # TODO: This only does the right thing for prod because prod authenticates to
# staging with the zulip.com deployment key, while staging is technically the # staging with the zulip.com deployment key, while staging is technically the

View File

@ -19,13 +19,12 @@ from .error_notify import notify_server_error, notify_browser_error
import time import time
from six import text_type from typing import Dict, Optional, Any, Text
from typing import Dict, Optional, Any
client = get_redis_client() client = get_redis_client()
def has_enough_time_expired_since_last_message(sender_email, min_delay): def has_enough_time_expired_since_last_message(sender_email, min_delay):
# type: (text_type, float) -> bool # type: (Text, float) -> bool
# This function returns a boolean, but it also has the side effect # This function returns a boolean, but it also has the side effect
# of noting that a new message was received. # of noting that a new message was received.
key = 'zilencer:feedback:%s' % (sender_email,) key = 'zilencer:feedback:%s' % (sender_email,)
@ -48,7 +47,7 @@ def get_ticket_number():
@has_request_variables @has_request_variables
def submit_feedback(request, deployment, message=REQ(validator=check_dict([]))): def submit_feedback(request, deployment, message=REQ(validator=check_dict([]))):
# type: (HttpRequest, Deployment, Dict[str, text_type]) -> HttpResponse # type: (HttpRequest, Deployment, Dict[str, Text]) -> HttpResponse
domainish = message["sender_domain"] domainish = message["sender_domain"]
if get_realm_by_string_id("zulip") not in deployment.realms.all(): if get_realm_by_string_id("zulip") not in deployment.realms.all():
domainish += u" via " + deployment.name domainish += u" via " + deployment.name
@ -84,11 +83,11 @@ def submit_feedback(request, deployment, message=REQ(validator=check_dict([]))):
@has_request_variables @has_request_variables
def report_error(request, deployment, type=REQ(), report=REQ(validator=check_dict([]))): def report_error(request, deployment, type=REQ(), report=REQ(validator=check_dict([]))):
# type: (HttpRequest, Deployment, text_type, Dict[str, Any]) -> HttpResponse # type: (HttpRequest, Deployment, Text, Dict[str, Any]) -> HttpResponse
return do_report_error(deployment.name, type, report) return do_report_error(deployment.name, type, report)
def do_report_error(deployment_name, type, report): def do_report_error(deployment_name, type, report):
# type: (text_type, text_type, Dict[str, Any]) -> HttpResponse # type: (Text, Text, Dict[str, Any]) -> HttpResponse
report['deployment'] = deployment_name report['deployment'] = deployment_name
if type == 'browser': if type == 'browser':
notify_browser_error(report) notify_browser_error(report)

View File

@ -1,8 +1,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import logging import logging
from typing import Any, Set, Tuple, Optional from typing import Any, Set, Tuple, Optional, Text
from six import text_type
from django.contrib.auth.backends import RemoteUserBackend from django.contrib.auth.backends import RemoteUserBackend
from django.conf import settings from django.conf import settings
@ -25,7 +24,7 @@ from django.contrib.auth import authenticate
from zerver.lib.utils import check_subdomain, get_subdomain from zerver.lib.utils import check_subdomain, get_subdomain
def pad_method_dict(method_dict): def pad_method_dict(method_dict):
# type: (Dict[text_type, bool]) -> Dict[text_type, bool] # type: (Dict[Text, bool]) -> Dict[Text, bool]
"""Pads an authentication methods dict to contain all auth backends """Pads an authentication methods dict to contain all auth backends
supported by the software, regardless of whether they are supported by the software, regardless of whether they are
configured on this server""" configured on this server"""
@ -35,7 +34,7 @@ def pad_method_dict(method_dict):
return method_dict return method_dict
def auth_enabled_helper(backends_to_check, realm): def auth_enabled_helper(backends_to_check, realm):
# type: (List[text_type], Optional[Realm]) -> bool # type: (List[Text], Optional[Realm]) -> bool
if realm is not None: if realm is not None:
enabled_method_dict = realm.authentication_methods_dict() enabled_method_dict = realm.authentication_methods_dict()
pad_method_dict(enabled_method_dict) pad_method_dict(enabled_method_dict)
@ -74,7 +73,7 @@ def github_auth_enabled(realm=None):
return auth_enabled_helper([u'GitHub'], realm) return auth_enabled_helper([u'GitHub'], realm)
def common_get_active_user_by_email(email, return_data=None): def common_get_active_user_by_email(email, return_data=None):
# type: (text_type, Optional[Dict[str, Any]]) -> Optional[UserProfile] # type: (Text, Optional[Dict[str, Any]]) -> Optional[UserProfile]
try: try:
user_profile = get_user_profile_by_email(email) user_profile = get_user_profile_by_email(email)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
@ -99,14 +98,14 @@ class ZulipAuthMixin(object):
return None return None
class SocialAuthMixin(ZulipAuthMixin): class SocialAuthMixin(ZulipAuthMixin):
auth_backend_name = None # type: text_type auth_backend_name = None # type: Text
def get_email_address(self, *args, **kwargs): def get_email_address(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type # type: (*Any, **Any) -> Text
raise NotImplementedError raise NotImplementedError
def get_full_name(self, *args, **kwargs): def get_full_name(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type # type: (*Any, **Any) -> Text
raise NotImplementedError raise NotImplementedError
def authenticate(self, *args, **kwargs): def authenticate(self, *args, **kwargs):
@ -172,7 +171,7 @@ class ZulipDummyBackend(ZulipAuthMixin):
def authenticate(self, username=None, realm_subdomain=None, use_dummy_backend=False, def authenticate(self, username=None, realm_subdomain=None, use_dummy_backend=False,
return_data=None): return_data=None):
# type: (Optional[text_type], Optional[text_type], bool, Optional[Dict[str, Any]]) -> Optional[UserProfile] # type: (Optional[Text], Optional[Text], bool, Optional[Dict[str, Any]]) -> Optional[UserProfile]
if use_dummy_backend: if use_dummy_backend:
user_profile = common_get_active_user_by_email(username) user_profile = common_get_active_user_by_email(username)
if user_profile is None: if user_profile is None:
@ -192,7 +191,7 @@ class EmailAuthBackend(ZulipAuthMixin):
""" """
def authenticate(self, username=None, password=None, realm_subdomain=None, return_data=None): def authenticate(self, username=None, password=None, realm_subdomain=None, return_data=None):
# type: (Optional[text_type], Optional[str], Optional[text_type], Optional[Dict[str, Any]]) -> Optional[UserProfile] # type: (Optional[Text], Optional[str], Optional[Text], Optional[Dict[str, Any]]) -> Optional[UserProfile]
""" Authenticate a user based on email address as the user name. """ """ Authenticate a user based on email address as the user name. """
if username is None or password is None: if username is None or password is None:
# Return immediately. Otherwise we will look for a SQL row with # Return immediately. Otherwise we will look for a SQL row with
@ -231,7 +230,7 @@ class GoogleMobileOauth2Backend(ZulipAuthMixin):
""" """
def authenticate(self, google_oauth2_token=None, realm_subdomain=None, return_data={}): def authenticate(self, google_oauth2_token=None, realm_subdomain=None, return_data={}):
# type: (Optional[str], Optional[text_type], Dict[str, Any]) -> Optional[UserProfile] # type: (Optional[str], Optional[Text], Dict[str, Any]) -> Optional[UserProfile]
try: try:
token_payload = googleapiclient.verify_id_token(google_oauth2_token, settings.GOOGLE_CLIENT_ID) token_payload = googleapiclient.verify_id_token(google_oauth2_token, settings.GOOGLE_CLIENT_ID)
except AppIdentityError: except AppIdentityError:
@ -262,7 +261,7 @@ class ZulipRemoteUserBackend(RemoteUserBackend):
create_unknown_user = False create_unknown_user = False
def authenticate(self, remote_user, realm_subdomain=None): def authenticate(self, remote_user, realm_subdomain=None):
# type: (str, Optional[text_type]) -> Optional[UserProfile] # type: (str, Optional[Text]) -> Optional[UserProfile]
if not remote_user: if not remote_user:
return None return None
@ -304,7 +303,7 @@ class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend):
return set() return set()
def django_to_ldap_username(self, username): def django_to_ldap_username(self, username):
# type: (text_type) -> text_type # type: (Text) -> Text
if settings.LDAP_APPEND_DOMAIN: if settings.LDAP_APPEND_DOMAIN:
if not username.endswith("@" + settings.LDAP_APPEND_DOMAIN): if not username.endswith("@" + settings.LDAP_APPEND_DOMAIN):
raise ZulipLDAPException("Username does not match LDAP domain.") raise ZulipLDAPException("Username does not match LDAP domain.")
@ -319,7 +318,7 @@ class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend):
class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase): class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
def authenticate(self, username, password, realm_subdomain=None, return_data=None): def authenticate(self, username, password, realm_subdomain=None, return_data=None):
# type: (text_type, str, Optional[text_type], Optional[Dict[str, Any]]) -> Optional[UserProfile] # type: (Text, str, Optional[Text], Optional[Dict[str, Any]]) -> Optional[UserProfile]
try: try:
username = self.django_to_ldap_username(username) username = self.django_to_ldap_username(username)
user_profile = ZulipLDAPAuthBackendBase.authenticate(self, username, password) user_profile = ZulipLDAPAuthBackendBase.authenticate(self, username, password)
@ -360,14 +359,14 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
# Just like ZulipLDAPAuthBackend, but doesn't let you log in. # Just like ZulipLDAPAuthBackend, but doesn't let you log in.
class ZulipLDAPUserPopulator(ZulipLDAPAuthBackendBase): class ZulipLDAPUserPopulator(ZulipLDAPAuthBackendBase):
def authenticate(self, username, password, realm_subdomain=None): def authenticate(self, username, password, realm_subdomain=None):
# type: (text_type, str, Optional[text_type]) -> None # type: (Text, str, Optional[Text]) -> None
return None return None
class DevAuthBackend(ZulipAuthMixin): class DevAuthBackend(ZulipAuthMixin):
# Allow logging in as any user without a password. # Allow logging in as any user without a password.
# This is used for convenience when developing Zulip. # This is used for convenience when developing Zulip.
def authenticate(self, username, realm_subdomain=None, return_data=None): def authenticate(self, username, realm_subdomain=None, return_data=None):
# type: (text_type, Optional[text_type], Optional[Dict[str, Any]]) -> Optional[UserProfile] # type: (Text, Optional[Text], Optional[Dict[str, Any]]) -> Optional[UserProfile]
user_profile = common_get_active_user_by_email(username, return_data=return_data) user_profile = common_get_active_user_by_email(username, return_data=return_data)
if user_profile is None: if user_profile is None:
return None return None
@ -379,14 +378,14 @@ class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2):
auth_backend_name = u"GitHub" auth_backend_name = u"GitHub"
def get_email_address(self, *args, **kwargs): def get_email_address(self, *args, **kwargs):
# type: (*Any, **Any) -> Optional[text_type] # type: (*Any, **Any) -> Optional[Text]
try: try:
return kwargs['response']['email'] return kwargs['response']['email']
except KeyError: except KeyError:
return None return None
def get_full_name(self, *args, **kwargs): def get_full_name(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type # type: (*Any, **Any) -> Text
try: try:
return kwargs['response']['name'] return kwargs['response']['name']
except KeyError: except KeyError:
@ -432,4 +431,4 @@ AUTH_BACKEND_NAME_MAP = {
u'Google': GoogleMobileOauth2Backend, u'Google': GoogleMobileOauth2Backend,
u'LDAP': ZulipLDAPAuthBackend, u'LDAP': ZulipLDAPAuthBackend,
u'RemoteUser': ZulipRemoteUserBackend, u'RemoteUser': ZulipRemoteUserBackend,
} # type: Dict[text_type, Any] } # type: Dict[Text, Any]

View File

@ -1,8 +1,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import sys import sys
from typing import Any, Optional, Union from typing import Any, Optional, Union, Text
from six import text_type
import jinja2 import jinja2
from django.utils import six from django.utils import six
@ -60,7 +59,7 @@ class Template(django_jinja2.Template):
super(Template, self).__init__(template, *args, **kwargs) super(Template, self).__init__(template, *args, **kwargs)
def render(self, context=None, request=None): def render(self, context=None, request=None):
# type: (Optional[Union[Dict[str, Any], Context]], Optional[HttpRequest]) -> text_type # type: (Optional[Union[Dict[str, Any], Context]], Optional[HttpRequest]) -> Text
if context is None: if context is None:
context = {} context = {}

View File

@ -3,7 +3,7 @@
""" """
from __future__ import absolute_import # Python 2 only from __future__ import absolute_import # Python 2 only
from six import text_type from typing import Text
from django.conf import settings from django.conf import settings
from django.template import TemplateSyntaxError from django.template import TemplateSyntaxError
@ -12,7 +12,7 @@ from zerver.templatetags.minified_js import MinifiedJSNode
def minified_js(sourcefile): def minified_js(sourcefile):
# type: (str) -> text_type # type: (str) -> Text
if sourcefile not in settings.JS_SPECS: if sourcefile not in settings.JS_SPECS:
raise TemplateSyntaxError( raise TemplateSyntaxError(
"Invalid argument: no JS file %s".format(sourcefile)) "Invalid argument: no JS file %s".format(sourcefile))