diff --git a/tools/run-mypy b/tools/run-mypy index 0e24d07..0675e6d 100755 --- a/tools/run-mypy +++ b/tools/run-mypy @@ -124,6 +124,7 @@ mypy_command = "mypy" extra_args = ["--check-untyped-defs", "--follow-imports=silent", "--scripts-are-modules", + "--disallow-any=generics", "-i"] if args.disallow_untyped_defs: extra_args.append("--disallow-untyped-defs") diff --git a/zulip/integrations/jabber/jabber_mirror_backend.py b/zulip/integrations/jabber/jabber_mirror_backend.py index 1ca3830..7c12755 100755 --- a/zulip/integrations/jabber/jabber_mirror_backend.py +++ b/zulip/integrations/jabber/jabber_mirror_backend.py @@ -301,10 +301,10 @@ class ZulipToJabberBot(object): def get_rooms(zulipToJabber): # type: (ZulipToJabberBot) -> List[str] def get_stream_infos(key, method): - # type: (str, Callable) -> Any + # type: (str, Callable[[], Dict[str, Any]]) -> Any ret = method() if ret.get("result") != "success": - logging.error(ret) + logging.error(str(ret)) sys.exit("Could not get initial list of Zulip %s" % (key,)) return ret[key] diff --git a/zulip/integrations/zephyr/zephyr_mirror_backend.py b/zulip/integrations/zephyr/zephyr_mirror_backend.py index cfae3b6..77f495f 100755 --- a/zulip/integrations/zephyr/zephyr_mirror_backend.py +++ b/zulip/integrations/zephyr/zephyr_mirror_backend.py @@ -252,7 +252,7 @@ def maybe_restart_mirroring_script(): time.sleep(1) def process_loop(log): - # type: (IO) -> None + # type: (IO[Any]) -> None restart_check_count = 0 last_check_time = time.time() while True: @@ -362,7 +362,7 @@ def decrypt_zephyr(zephyr_class, instance, body): return decrypted def process_notice(notice, log): - # type: (zulip, IO) -> None + # type: (zulip, IO[Any]) -> None (zsig, body) = parse_zephyr_body(notice.message, notice.format) is_personal = False is_huddle = False @@ -579,7 +579,7 @@ def zephyr_to_zulip(options): process_loop(None) def send_zephyr(zwrite_args, content): - # type: (List, str) -> Tuple[int, str] + # type: (List[str], 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")) @@ -969,7 +969,7 @@ def configure_logger(logger, direction_name): handler.setFormatter(formatter) def parse_args(): - # type: () -> Tuple + # type: () -> Tuple[Any, ...] parser = optparse.OptionParser() parser.add_option('--forward-class-messages', default=False, diff --git a/zulip/zulip/__init__.py b/zulip/zulip/__init__.py index 11a2a51..1a6c686 100644 --- a/zulip/zulip/__init__.py +++ b/zulip/zulip/__init__.py @@ -435,7 +435,7 @@ class Client(object): ) def do_api_query(self, orig_request, url, method="POST", longpolling=False, files=None): - # type: (Mapping[str, Any], str, str, bool, List[IO]) -> Dict[str, Any] + # type: (Mapping[str, Any], str, str, bool, List[IO[Any]]) -> Dict[str, Any] if files is None: files = [] @@ -568,14 +568,14 @@ class Client(object): "status_code": res.status_code} def call_endpoint(self, url=None, method="POST", request=None, longpolling=False, files=None): - # type: (str, str, Dict[str, Any], bool, List[IO]) -> Dict[str, Any] + # type: (str, str, Dict[str, Any], bool, List[IO[Any]]) -> Dict[str, Any] if request is None: request = dict() return self.do_api_query(request, API_VERSTRING + url, method=method, longpolling=longpolling, files=files) def call_on_each_event(self, callback, event_types=None, narrow=None): - # type: (Callable, Optional[List[str]], Any) -> None + # type: (Callable[[Any], None], Optional[List[str]], Any) -> None if narrow is None: narrow = [] @@ -635,7 +635,7 @@ class Client(object): callback(event) def call_on_each_message(self, callback): - # type: (Callable) -> None + # type: (Callable[[Any], None]) -> None def event_callback(event): # type: (Dict[str, str]) -> None if event['type'] == 'message': @@ -653,7 +653,7 @@ class Client(object): ) def upload_file(self, file): - # type: (IO) -> Dict[str, Any] + # type: (IO[Any]) -> Dict[str, Any] ''' See examples/upload-file for example usage. ''' diff --git a/zulip/zulip/examples/upload-file b/zulip/zulip/examples/upload-file index 8901d59..29e5a35 100755 --- a/zulip/zulip/examples/upload-file +++ b/zulip/zulip/examples/upload-file @@ -25,7 +25,7 @@ from __future__ import print_function import argparse from six.moves import StringIO as _StringIO -from typing import IO +from typing import IO, Any import zulip class StringIO(_StringIO): @@ -47,7 +47,7 @@ options = parser.parse_args() client = zulip.init_from_options(options) -file = None # type: IO +file = None # type: IO[Any] if options.file_path: file = open(options.file_path, 'rb') else: diff --git a/zulip_bots/zulip_bots/bots/chess/chess.py b/zulip_bots/zulip_bots/bots/chess/chess.py index 2cd4ffa..7dafbf4 100644 --- a/zulip_bots/zulip_bots/bots/chess/chess.py +++ b/zulip_bots/zulip_bots/bots/chess/chess.py @@ -2,8 +2,7 @@ import chess import chess.uci import re import copy -from typing import Any, Optional -from zulip_bots.lib import ExternalBotHandler +from typing import Any, Optional, Dict START_REGEX = re.compile('start with other user$') START_COMPUTER_REGEX = re.compile( @@ -23,7 +22,7 @@ class ChessHandler(object): 'Stockfish program on this computer.' ) - def initialize(self, bot_handler: ExternalBotHandler) -> None: + def initialize(self, bot_handler: Any) -> None: self.config_info = bot_handler.get_config_info('chess') try: @@ -38,8 +37,8 @@ class ChessHandler(object): def handle_message( self, - message: dict, - bot_handler: ExternalBotHandler + message: Dict[str, str], + bot_handler: Any ) -> None: content = message['content'] @@ -94,7 +93,7 @@ class ChessHandler(object): last_fen ) - def start(self, message: dict, bot_handler: ExternalBotHandler) -> None: + def start(self, message: Dict[str, str], bot_handler: Any) -> None: """Starts a game with another user, with the current user as white. Replies to the bot handler. @@ -115,8 +114,8 @@ class ChessHandler(object): def start_computer( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, is_white_user: bool ) -> None: """Starts a game with the computer. Replies to the bot handler. @@ -151,8 +150,8 @@ class ChessHandler(object): def validate_board( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, fen: str ) -> Optional[chess.Board]: """Validates a board based on its FEN string. Replies to the bot @@ -179,8 +178,8 @@ class ChessHandler(object): def validate_move( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, last_board: chess.Board, move_san: str, is_computer: object @@ -223,8 +222,8 @@ class ChessHandler(object): def check_game_over( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, new_board: chess.Board ) -> bool: """Checks if a game is over due to @@ -280,8 +279,8 @@ class ChessHandler(object): def move( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, last_fen: str, move_san: str ) -> None: @@ -325,8 +324,8 @@ class ChessHandler(object): def move_computer( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, last_fen: str, move_san: str ) -> None: @@ -396,8 +395,8 @@ class ChessHandler(object): def move_computer_first( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, last_fen: str ) -> None: """Preforms a move for the computer without having the user go first in @@ -447,8 +446,8 @@ class ChessHandler(object): def resign( self, - message: dict, - bot_handler: ExternalBotHandler, + message: Dict[str, str], + bot_handler: Any, last_fen: str ) -> None: """Resigns the game for the current player. diff --git a/zulip_bots/zulip_bots/bots/incrementor/incrementor.py b/zulip_bots/zulip_bots/bots/incrementor/incrementor.py index 6a0994e..d4bb50b 100644 --- a/zulip_bots/zulip_bots/bots/incrementor/incrementor.py +++ b/zulip_bots/zulip_bots/bots/incrementor/incrementor.py @@ -1,6 +1,6 @@ # See readme.md for instructions on running this code. -from zulip_bots.lib import ExternalBotHandler +from typing import Dict, Any class IncrementorHandler(object): META = { @@ -16,13 +16,13 @@ class IncrementorHandler(object): is @-mentioned, this number will be incremented in the same message. ''' - def initialize(self, bot_handler: ExternalBotHandler) -> None: + def initialize(self, bot_handler: Any) -> None: storage = bot_handler.storage if not storage.contains('number') or not storage.contains('message_id'): storage.put('number', 0) storage.put('message_id', None) - def handle_message(self, message: dict, bot_handler: ExternalBotHandler) -> None: + def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None: storage = bot_handler.storage num = storage.get('number') diff --git a/zulip_bots/zulip_bots/bots/wikipedia/wikipedia.py b/zulip_bots/zulip_bots/bots/wikipedia/wikipedia.py index 5373639..b9fa991 100644 --- a/zulip_bots/zulip_bots/bots/wikipedia/wikipedia.py +++ b/zulip_bots/zulip_bots/bots/wikipedia/wikipedia.py @@ -4,8 +4,9 @@ import requests import logging import re from six.moves import urllib -from zulip_bots.lib import ExternalBotHandler -from typing import Optional +from zulip_bots.lib import Any + +from typing import Optional, Any, Dict # See readme.md for instructions on running this code. @@ -34,11 +35,11 @@ class WikipediaHandler(object): should preface searches with "@mention-bot". @mention-bot ''' - def handle_message(self, message: dict, bot_handler: ExternalBotHandler) -> None: + def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None: bot_response = self.get_bot_wiki_response(message, bot_handler) bot_handler.send_reply(message, bot_response) - def get_bot_wiki_response(self, message: dict, bot_handler: ExternalBotHandler) -> Optional[str]: + def get_bot_wiki_response(self, message: Dict[str, str], bot_handler: Any) -> Optional[str]: '''This function returns the URLs of the requested topic.''' help_text = 'Please enter your search term after @mention-bot' diff --git a/zulip_bots/zulip_bots/bots/xkcd/xkcd.py b/zulip_bots/zulip_bots/bots/xkcd/xkcd.py index ec5f198..e12616e 100644 --- a/zulip_bots/zulip_bots/bots/xkcd/xkcd.py +++ b/zulip_bots/zulip_bots/bots/xkcd/xkcd.py @@ -2,7 +2,8 @@ import random import logging import requests -from zulip_bots.lib import ExternalBotHandler + +from typing import Any, Dict XKCD_TEMPLATE_URL = 'https://xkcd.com/%s/info.0.json' LATEST_XKCD_URL = 'https://xkcd.com/info.0.json' @@ -33,7 +34,7 @@ class XkcdHandler(object): ``, e.g `@mention-bot 1234`. ''' - def handle_message(self, message: dict, bot_handler: ExternalBotHandler) -> None: + def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None: xkcd_bot_response = get_xkcd_bot_response(message) bot_handler.send_reply(message, xkcd_bot_response) @@ -48,7 +49,7 @@ class XkcdNotFoundError(Exception): class XkcdServerError(Exception): pass -def get_xkcd_bot_response(message: dict) -> str: +def get_xkcd_bot_response(message: Dict[str, str]) -> str: original_content = message['content'].strip() command = original_content.strip() @@ -83,7 +84,7 @@ def get_xkcd_bot_response(message: dict) -> str: fetched['alt'], fetched['img'])) -def fetch_xkcd_query(mode: int, comic_id: str = None) -> dict: +def fetch_xkcd_query(mode: int, comic_id: str = None) -> Dict[str, str]: try: if mode == XkcdBotCommand.LATEST: # Fetch the latest comic strip. url = LATEST_XKCD_URL diff --git a/zulip_bots/zulip_bots/bots/yoda/yoda.py b/zulip_bots/zulip_bots/bots/yoda/yoda.py index 5236479..c5a1d00 100644 --- a/zulip_bots/zulip_bots/bots/yoda/yoda.py +++ b/zulip_bots/zulip_bots/bots/yoda/yoda.py @@ -4,13 +4,14 @@ from __future__ import print_function import logging import ssl import sys -from zulip_bots.lib import ExternalBotHandler try: import requests except ImportError as e: logging.error("Dependency missing!!\n{}".format(e)) sys.exit(0) +from typing import Any, Dict + HELP_MESSAGE = ''' This bot allows users to translate a sentence into 'Yoda speak'. @@ -38,7 +39,7 @@ class YodaSpeakHandler(object): This bot will allow users to translate a sentence into 'Yoda speak'. It looks for messages starting with '@mention-bot'. ''' - def initialize(self, bot_handler: ExternalBotHandler) -> None: + def initialize(self, bot_handler: Any) -> None: self.api_key = bot_handler.get_config_info('yoda')['api_key'] def usage(self) -> str: @@ -55,7 +56,7 @@ class YodaSpeakHandler(object): @mention-bot You will learn how to speak like me someday. ''' - def handle_message(self, message: dict, bot_handler: ExternalBotHandler) -> None: + def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None: self.handle_input(message, bot_handler) def send_to_yoda_api(self, sentence: str) -> str: @@ -88,7 +89,7 @@ class YodaSpeakHandler(object): sentence = message_content.replace(' ', '+') return sentence - def handle_input(self, message: dict, bot_handler: ExternalBotHandler) -> None: + def handle_input(self, message: Dict[str, str], bot_handler: Any) -> None: original_content = message['content'] if self.is_help(original_content) or (original_content == ""): @@ -113,7 +114,7 @@ class YodaSpeakHandler(object): bot_handler.send_reply(message, reply_message) - def send_message(self, bot_handler: ExternalBotHandler, message: str, stream: str, subject: str) -> None: + def send_message(self, bot_handler: Any, message: str, stream: str, subject: str) -> None: # function for sending a message bot_handler.send_message(dict( type='stream',