typing: Convert function type annotations to Python 3 style.
Generated by com2ann (slightly patched to avoid also converting assignment type annotations, which require Python 3.6), followed by some manual whitespace adjustment, and two fixes for use-before-define issues: - def set_zulip_client(self, zulipToJabberClient: ZulipToJabberBot) -> None: + def set_zulip_client(self, zulipToJabberClient: 'ZulipToJabberBot') -> None: -def init_from_options(options: Any, client: Optional[str] = None) -> Client: +def init_from_options(options: Any, client: Optional[str] = None) -> 'Client': Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
parent
7c5f73dce9
commit
5428c5f296
42 changed files with 311 additions and 577 deletions
|
@ -82,8 +82,7 @@ else:
|
|||
("tabbott-nagios-test", "a"),
|
||||
]
|
||||
|
||||
def print_status_and_exit(status):
|
||||
# type: (int) -> None
|
||||
def print_status_and_exit(status: int) -> None:
|
||||
|
||||
# The output of this script is used by Nagios. Various outputs,
|
||||
# e.g. true success and punting due to a SERVNAK, result in a
|
||||
|
@ -92,8 +91,7 @@ def print_status_and_exit(status):
|
|||
print(status)
|
||||
sys.exit(status)
|
||||
|
||||
def send_zulip(message):
|
||||
# type: (Dict[str, str]) -> None
|
||||
def send_zulip(message: Dict[str, str]) -> None:
|
||||
result = zulip_client.send_message(message)
|
||||
if result["result"] != "success":
|
||||
logger.error("Error sending zulip, args were:")
|
||||
|
@ -102,8 +100,7 @@ def send_zulip(message):
|
|||
print_status_and_exit(1)
|
||||
|
||||
# Returns True if and only if we "Detected server failure" sending the zephyr.
|
||||
def send_zephyr(zwrite_args, content):
|
||||
# type: (List[str], str) -> bool
|
||||
def send_zephyr(zwrite_args: List[str], content: str) -> bool:
|
||||
p = subprocess.Popen(zwrite_args, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate(input=content.encode("utf-8"))
|
||||
|
@ -167,16 +164,14 @@ if not actually_subscribed:
|
|||
# Prepare keys
|
||||
zhkeys = {} # type: Dict[str, Tuple[str, str]]
|
||||
hzkeys = {} # type: Dict[str, Tuple[str, str]]
|
||||
def gen_key(key_dict):
|
||||
# type: (Dict[str, Any]) -> str
|
||||
def gen_key(key_dict: Dict[str, Any]) -> str:
|
||||
bits = str(random.getrandbits(32))
|
||||
while bits in key_dict:
|
||||
# Avoid the unlikely event that we get the same bits twice
|
||||
bits = str(random.getrandbits(32))
|
||||
return bits
|
||||
|
||||
def gen_keys(key_dict):
|
||||
# type: (Dict[str, Tuple[str, str]]) -> None
|
||||
def gen_keys(key_dict: Dict[str, Tuple[str, str]]) -> None:
|
||||
for (stream, test) in test_streams:
|
||||
key_dict[gen_key(key_dict)] = (stream, test)
|
||||
|
||||
|
@ -188,8 +183,7 @@ notices = []
|
|||
# We check for new zephyrs multiple times, to avoid filling the zephyr
|
||||
# receive queue with 30+ messages, which might result in messages
|
||||
# being dropped.
|
||||
def receive_zephyrs():
|
||||
# type: () -> None
|
||||
def receive_zephyrs() -> None:
|
||||
while True:
|
||||
try:
|
||||
notice = zephyr.receive(block=False)
|
||||
|
@ -271,8 +265,7 @@ receive_zephyrs()
|
|||
logger.info("Finished receiving Zephyr messages!")
|
||||
|
||||
all_keys = set(list(zhkeys.keys()) + list(hzkeys.keys()))
|
||||
def process_keys(content_list):
|
||||
# type: (List[str]) -> Tuple[Dict[str, int], Set[str], Set[str], bool, bool]
|
||||
def process_keys(content_list: List[str]) -> Tuple[Dict[str, int], Set[str], Set[str], bool, bool]:
|
||||
|
||||
# Start by filtering out any keys that might have come from
|
||||
# concurrent check-mirroring processes
|
||||
|
|
|
@ -13,8 +13,7 @@ import zulip
|
|||
|
||||
from typing import Set, Optional
|
||||
|
||||
def fetch_public_streams():
|
||||
# type: () -> Optional[Set[bytes]]
|
||||
def fetch_public_streams() -> Optional[Set[bytes]]:
|
||||
public_streams = set()
|
||||
|
||||
try:
|
||||
|
|
|
@ -14,8 +14,7 @@ from zephyr_mirror_backend import parse_args
|
|||
from types import FrameType
|
||||
from typing import Any
|
||||
|
||||
def die(signal, frame):
|
||||
# type: (int, FrameType) -> None
|
||||
def die(signal: int, frame: FrameType) -> None:
|
||||
|
||||
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
|
||||
os._exit(1)
|
||||
|
@ -40,8 +39,7 @@ if options.forward_class_messages and not options.noshard:
|
|||
print("Starting parallel zephyr class mirroring bot")
|
||||
jobs = list("0123456789abcdef")
|
||||
|
||||
def run_job(shard):
|
||||
# type: (str) -> int
|
||||
def run_job(shard: str) -> int:
|
||||
subprocess.call(args + ["--shard=%s" % (shard,)])
|
||||
return 0
|
||||
for (status, job) in run_parallel(run_job, jobs, threads=16):
|
||||
|
|
|
@ -26,8 +26,7 @@ CURRENT_STATE = States.Startup
|
|||
|
||||
logger = cast(logging.Logger, None) # type: logging.Logger # FIXME cast should not be needed?
|
||||
|
||||
def to_zulip_username(zephyr_username):
|
||||
# type: (str) -> str
|
||||
def to_zulip_username(zephyr_username: str) -> str:
|
||||
if "@" in zephyr_username:
|
||||
(user, realm) = zephyr_username.split("@")
|
||||
else:
|
||||
|
@ -39,8 +38,7 @@ def to_zulip_username(zephyr_username):
|
|||
return user.lower() + "@mit.edu"
|
||||
return user.lower() + "|" + realm.upper() + "@mit.edu"
|
||||
|
||||
def to_zephyr_username(zulip_username):
|
||||
# type: (str) -> str
|
||||
def to_zephyr_username(zulip_username: str) -> str:
|
||||
(user, realm) = zulip_username.split("@")
|
||||
if "|" not in user:
|
||||
# Hack to make ctl's fake username setup work :)
|
||||
|
@ -62,8 +60,7 @@ def to_zephyr_username(zulip_username):
|
|||
# characters (our assumed minimum linewrapping threshold for Zephyr)
|
||||
# or (3) the first word of the next line is longer than this entire
|
||||
# line.
|
||||
def different_paragraph(line, next_line):
|
||||
# type: (str, str) -> bool
|
||||
def different_paragraph(line: str, next_line: str) -> bool:
|
||||
words = next_line.split()
|
||||
return (len(line + " " + words[0]) < len(next_line) * 0.8 or
|
||||
len(line + " " + words[0]) < 50 or
|
||||
|
@ -71,8 +68,7 @@ def different_paragraph(line, next_line):
|
|||
|
||||
# Linewrapping algorithm based on:
|
||||
# http://gcbenison.wordpress.com/2011/07/03/a-program-to-intelligently-remove-carriage-returns-so-you-can-paste-text-without-having-it-look-awful/ #ignorelongline
|
||||
def unwrap_lines(body):
|
||||
# type: (str) -> str
|
||||
def unwrap_lines(body: str) -> str:
|
||||
lines = body.split("\n")
|
||||
result = ""
|
||||
previous_line = lines[0]
|
||||
|
@ -95,8 +91,7 @@ def unwrap_lines(body):
|
|||
result += previous_line
|
||||
return result
|
||||
|
||||
def send_zulip(zeph):
|
||||
# type: (Dict[str, str]) -> Dict[str, str]
|
||||
def send_zulip(zeph: Dict[str, str]) -> Dict[str, str]:
|
||||
message = {}
|
||||
if options.forward_class_messages:
|
||||
message["forged"] = "yes"
|
||||
|
@ -128,8 +123,7 @@ def send_zulip(zeph):
|
|||
|
||||
return zulip_client.send_message(message)
|
||||
|
||||
def send_error_zulip(error_msg):
|
||||
# type: (str) -> None
|
||||
def send_error_zulip(error_msg: str) -> None:
|
||||
message = {"type": "private",
|
||||
"sender": zulip_account_email,
|
||||
"to": zulip_account_email,
|
||||
|
@ -138,8 +132,7 @@ def send_error_zulip(error_msg):
|
|||
zulip_client.send_message(message)
|
||||
|
||||
current_zephyr_subs = set()
|
||||
def zephyr_bulk_subscribe(subs):
|
||||
# type: (List[Tuple[str, str, str]]) -> None
|
||||
def zephyr_bulk_subscribe(subs: List[Tuple[str, str, str]]) -> None:
|
||||
try:
|
||||
zephyr._z.subAll(subs)
|
||||
except OSError:
|
||||
|
@ -174,8 +167,7 @@ def zephyr_bulk_subscribe(subs):
|
|||
else:
|
||||
current_zephyr_subs.add(cls)
|
||||
|
||||
def update_subscriptions():
|
||||
# type: () -> None
|
||||
def update_subscriptions() -> None:
|
||||
try:
|
||||
f = open(options.stream_file_path)
|
||||
public_streams = json.loads(f.read())
|
||||
|
@ -198,8 +190,7 @@ def update_subscriptions():
|
|||
if len(classes_to_subscribe) > 0:
|
||||
zephyr_bulk_subscribe(list(classes_to_subscribe))
|
||||
|
||||
def maybe_kill_child():
|
||||
# type: () -> None
|
||||
def maybe_kill_child() -> None:
|
||||
try:
|
||||
if child_pid is not None:
|
||||
os.kill(child_pid, signal.SIGTERM)
|
||||
|
@ -207,8 +198,7 @@ def maybe_kill_child():
|
|||
# We don't care if the child process no longer exists, so just log the error
|
||||
logger.exception("")
|
||||
|
||||
def maybe_restart_mirroring_script():
|
||||
# type: () -> None
|
||||
def maybe_restart_mirroring_script() -> None:
|
||||
if os.stat(os.path.join(options.stamp_path, "stamps", "restart_stamp")).st_mtime > start_time or \
|
||||
((options.user == "tabbott" or options.user == "tabbott/extra") and
|
||||
os.stat(os.path.join(options.stamp_path, "stamps", "tabbott_stamp")).st_mtime > start_time):
|
||||
|
@ -227,8 +217,7 @@ def maybe_restart_mirroring_script():
|
|||
logger.exception("Error restarting mirroring script; trying again... Traceback:")
|
||||
time.sleep(1)
|
||||
|
||||
def process_loop(log):
|
||||
# type: (Optional[IO[Any]]) -> None
|
||||
def process_loop(log: Optional[IO[Any]]) -> None:
|
||||
restart_check_count = 0
|
||||
last_check_time = time.time()
|
||||
while True:
|
||||
|
@ -267,8 +256,7 @@ def process_loop(log):
|
|||
except Exception:
|
||||
logger.exception("Error updating subscriptions from Zulip:")
|
||||
|
||||
def parse_zephyr_body(zephyr_data, notice_format):
|
||||
# type: (str, str) -> Tuple[str, str]
|
||||
def parse_zephyr_body(zephyr_data: str, notice_format: str) -> Tuple[str, str]:
|
||||
try:
|
||||
(zsig, body) = zephyr_data.split("\x00", 1)
|
||||
if (notice_format == 'New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4' or
|
||||
|
@ -284,8 +272,7 @@ def parse_zephyr_body(zephyr_data, notice_format):
|
|||
body = body.replace('\x00', '')
|
||||
return (zsig, body)
|
||||
|
||||
def parse_crypt_table(zephyr_class, instance):
|
||||
# type: (Text, str) -> Optional[str]
|
||||
def parse_crypt_table(zephyr_class: Text, instance: str) -> Optional[str]:
|
||||
try:
|
||||
crypt_table = open(os.path.join(os.environ["HOME"], ".crypt-table"))
|
||||
except OSError:
|
||||
|
@ -306,8 +293,7 @@ def parse_crypt_table(zephyr_class, instance):
|
|||
return groups["keypath"]
|
||||
return None
|
||||
|
||||
def decrypt_zephyr(zephyr_class, instance, body):
|
||||
# type: (Text, str, str) -> str
|
||||
def decrypt_zephyr(zephyr_class: Text, instance: str, body: str) -> str:
|
||||
keypath = parse_crypt_table(zephyr_class, instance)
|
||||
if keypath is None:
|
||||
# We can't decrypt it, so we just return the original body
|
||||
|
@ -337,8 +323,7 @@ def decrypt_zephyr(zephyr_class, instance, body):
|
|||
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
|
||||
return decrypted # type: ignore # bytes, expecting str
|
||||
|
||||
def process_notice(notice, log):
|
||||
# type: (Any, Optional[IO[Any]]) -> None
|
||||
def process_notice(notice: Any, log: Optional[IO[Any]]) -> None:
|
||||
(zsig, body) = parse_zephyr_body(notice.message, notice.format)
|
||||
is_personal = False
|
||||
is_huddle = False
|
||||
|
@ -436,8 +421,7 @@ def process_notice(notice, log):
|
|||
finally:
|
||||
os._exit(0)
|
||||
|
||||
def decode_unicode_byte_strings(zeph):
|
||||
# type: (Dict[str, Any]) -> Dict[str, str]
|
||||
def decode_unicode_byte_strings(zeph: Dict[str, Any]) -> Dict[str, str]:
|
||||
# 'Any' can be of any type of text that is converted to str.
|
||||
for field in zeph.keys():
|
||||
if isinstance(zeph[field], str):
|
||||
|
@ -448,14 +432,12 @@ def decode_unicode_byte_strings(zeph):
|
|||
zeph[field] = decoded
|
||||
return zeph
|
||||
|
||||
def quit_failed_initialization(message):
|
||||
# type: (str) -> str
|
||||
def quit_failed_initialization(message: str) -> str:
|
||||
logger.error(message)
|
||||
maybe_kill_child()
|
||||
sys.exit(1)
|
||||
|
||||
def zephyr_init_autoretry():
|
||||
# type: () -> None
|
||||
def zephyr_init_autoretry() -> None:
|
||||
backoff = zulip.RandomExponentialBackoff()
|
||||
while backoff.keep_going():
|
||||
try:
|
||||
|
@ -470,8 +452,7 @@ def zephyr_init_autoretry():
|
|||
|
||||
quit_failed_initialization("Could not initialize Zephyr library, quitting!")
|
||||
|
||||
def zephyr_load_session_autoretry(session_path):
|
||||
# type: (str) -> None
|
||||
def zephyr_load_session_autoretry(session_path: str) -> None:
|
||||
backoff = zulip.RandomExponentialBackoff()
|
||||
while backoff.keep_going():
|
||||
try:
|
||||
|
@ -486,8 +467,7 @@ def zephyr_load_session_autoretry(session_path):
|
|||
|
||||
quit_failed_initialization("Could not load saved Zephyr session, quitting!")
|
||||
|
||||
def zephyr_subscribe_autoretry(sub):
|
||||
# type: (Tuple[str, str, str]) -> None
|
||||
def zephyr_subscribe_autoretry(sub: Tuple[str, str, str]) -> None:
|
||||
backoff = zulip.RandomExponentialBackoff()
|
||||
while backoff.keep_going():
|
||||
try:
|
||||
|
@ -502,8 +482,7 @@ def zephyr_subscribe_autoretry(sub):
|
|||
|
||||
quit_failed_initialization("Could not subscribe to personals, quitting!")
|
||||
|
||||
def zephyr_to_zulip(options):
|
||||
# type: (Any) -> None
|
||||
def zephyr_to_zulip(options: Any) -> None:
|
||||
if options.use_sessions and os.path.exists(options.session_path):
|
||||
logger.info("Loading old session")
|
||||
zephyr_load_session_autoretry(options.session_path)
|
||||
|
@ -554,8 +533,7 @@ def zephyr_to_zulip(options):
|
|||
else:
|
||||
process_loop(None)
|
||||
|
||||
def send_zephyr(zwrite_args, content):
|
||||
# type: (List[str], str) -> Tuple[int, str]
|
||||
def send_zephyr(zwrite_args: List[str], content: str) -> Tuple[int, str]:
|
||||
p = subprocess.Popen(zwrite_args, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate(input=content.encode("utf-8"))
|
||||
|
@ -571,16 +549,13 @@ def send_zephyr(zwrite_args, content):
|
|||
logger.warning("stderr: " + stderr) # type: ignore # str + bytes
|
||||
return (p.returncode, stderr) # type: ignore # bytes vs str
|
||||
|
||||
def send_authed_zephyr(zwrite_args, content):
|
||||
# type: (List[str], str) -> Tuple[int, str]
|
||||
def send_authed_zephyr(zwrite_args: List[str], content: str) -> Tuple[int, str]:
|
||||
return send_zephyr(zwrite_args, content)
|
||||
|
||||
def send_unauthed_zephyr(zwrite_args, content):
|
||||
# type: (List[str], str) -> Tuple[int, str]
|
||||
def send_unauthed_zephyr(zwrite_args: List[str], content: str) -> Tuple[int, str]:
|
||||
return send_zephyr(zwrite_args + ["-d"], content)
|
||||
|
||||
def zcrypt_encrypt_content(zephyr_class, instance, content):
|
||||
# type: (str, str, str) -> Optional[str]
|
||||
def zcrypt_encrypt_content(zephyr_class: str, instance: str, content: str) -> Optional[str]:
|
||||
keypath = parse_crypt_table(zephyr_class, instance)
|
||||
if keypath is None:
|
||||
return None
|
||||
|
@ -605,8 +580,7 @@ def zcrypt_encrypt_content(zephyr_class, instance, content):
|
|||
encrypted, _ = p.communicate(input=content) # type: ignore # Optional[bytes] vs string
|
||||
return encrypted # type: ignore # bytes, expecting Optional[str]
|
||||
|
||||
def forward_to_zephyr(message):
|
||||
# type: (Dict[str, Any]) -> None
|
||||
def forward_to_zephyr(message: Dict[str, Any]) -> None:
|
||||
# 'Any' can be of any type of text
|
||||
support_heading = "Hi there! This is an automated message from Zulip."
|
||||
support_closing = """If you have any questions, please be in touch through the \
|
||||
|
@ -735,8 +709,7 @@ received it, Zephyr users did not. The error message from zwrite was:
|
|||
%s""" % (support_heading, stderr, support_closing))
|
||||
return
|
||||
|
||||
def maybe_forward_to_zephyr(message):
|
||||
# type: (Dict[str, Any]) -> None
|
||||
def maybe_forward_to_zephyr(message: Dict[str, Any]) -> None:
|
||||
# The key string can be used to direct any type of text.
|
||||
if (message["sender_email"] == zulip_account_email):
|
||||
if not ((message["type"] == "stream") or
|
||||
|
@ -758,8 +731,7 @@ def maybe_forward_to_zephyr(message):
|
|||
# whole process
|
||||
logger.exception("Error forwarding message:")
|
||||
|
||||
def zulip_to_zephyr(options):
|
||||
# type: (int) -> None
|
||||
def zulip_to_zephyr(options: int) -> None:
|
||||
# Sync messages from zulip to zephyr
|
||||
logger.info("Starting syncing messages.")
|
||||
while True:
|
||||
|
@ -769,8 +741,7 @@ def zulip_to_zephyr(options):
|
|||
logger.exception("Error syncing messages:")
|
||||
time.sleep(1)
|
||||
|
||||
def subscribed_to_mail_messages():
|
||||
# type: () -> bool
|
||||
def subscribed_to_mail_messages() -> bool:
|
||||
# In case we have lost our AFS tokens and those won't be able to
|
||||
# parse the Zephyr subs file, first try reading in result of this
|
||||
# query from the environment so we can avoid the filesystem read.
|
||||
|
@ -784,8 +755,7 @@ def subscribed_to_mail_messages():
|
|||
os.environ["HUMBUG_FORWARD_MAIL_ZEPHYRS"] = "False"
|
||||
return False
|
||||
|
||||
def add_zulip_subscriptions(verbose):
|
||||
# type: (bool) -> None
|
||||
def add_zulip_subscriptions(verbose: bool) -> None:
|
||||
zephyr_subscriptions = set()
|
||||
skipped = set()
|
||||
for (cls, instance, recipient) in parse_zephyr_subs(verbose=verbose):
|
||||
|
@ -871,12 +841,10 @@ to these .zephyrs.subs lines, please do so via the Zulip
|
|||
web interface.
|
||||
""")) + "\n")
|
||||
|
||||
def valid_stream_name(name):
|
||||
# type: (str) -> bool
|
||||
def valid_stream_name(name: str) -> bool:
|
||||
return name != ""
|
||||
|
||||
def parse_zephyr_subs(verbose=False):
|
||||
# type: (bool) -> Set[Tuple[str, str, str]]
|
||||
def parse_zephyr_subs(verbose: bool = False) -> Set[Tuple[str, str, str]]:
|
||||
zephyr_subscriptions = set() # type: Set[Tuple[str, str, str]]
|
||||
subs_file = os.path.join(os.environ["HOME"], ".zephyr.subs")
|
||||
if not os.path.exists(subs_file):
|
||||
|
@ -904,8 +872,7 @@ def parse_zephyr_subs(verbose=False):
|
|||
zephyr_subscriptions.add((cls.strip(), instance.strip(), recipient.strip()))
|
||||
return zephyr_subscriptions
|
||||
|
||||
def open_logger():
|
||||
# type: () -> logging.Logger
|
||||
def open_logger() -> logging.Logger:
|
||||
if options.log_path is not None:
|
||||
log_file = options.log_path
|
||||
elif options.forward_class_messages:
|
||||
|
@ -930,8 +897,7 @@ def open_logger():
|
|||
logger.addHandler(file_handler)
|
||||
return logger
|
||||
|
||||
def configure_logger(logger, direction_name):
|
||||
# type: (logging.Logger, Optional[str]) -> None
|
||||
def configure_logger(logger: logging.Logger, direction_name: Optional[str]) -> None:
|
||||
if direction_name is None:
|
||||
log_format = "%(message)s"
|
||||
else:
|
||||
|
@ -945,8 +911,7 @@ def configure_logger(logger, direction_name):
|
|||
for handler in root_logger.handlers:
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
def parse_args():
|
||||
# type: () -> Tuple[Any, ...]
|
||||
def parse_args() -> Tuple[Any, ...]:
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('--forward-class-messages',
|
||||
default=False,
|
||||
|
@ -1029,8 +994,7 @@ def parse_args():
|
|||
default=os.path.join(os.environ["HOME"], "Private", ".humbug-api-key"))
|
||||
return parser.parse_args()
|
||||
|
||||
def die_gracefully(signal, frame):
|
||||
# type: (int, FrameType) -> None
|
||||
def die_gracefully(signal: int, frame: FrameType) -> None:
|
||||
if CURRENT_STATE == States.ZulipToZephyr or CURRENT_STATE == States.ChildSending:
|
||||
# this is a child process, so we want os._exit (no clean-up necessary)
|
||||
os._exit(1)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue