Convert type comments to Python ≥ 3.6 variable annotations.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
8abca34a05
commit
a9607dfdf9
44 changed files with 128 additions and 142 deletions
|
@ -19,10 +19,10 @@ class HelloWorldHandler:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None:
|
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None:
|
||||||
content = "beep boop" # type: str
|
content = "beep boop"
|
||||||
bot_handler.send_reply(message, content)
|
bot_handler.send_reply(message, content)
|
||||||
|
|
||||||
emoji_name = "wave" # type: str
|
emoji_name = "wave"
|
||||||
bot_handler.react(message, emoji_name)
|
bot_handler.react(message, emoji_name)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from zulint.custom_rules import RuleList
|
from zulint.custom_rules import Rule, RuleList
|
||||||
|
|
||||||
MYPY = False
|
whitespace_rules: List[Rule] = [
|
||||||
if MYPY:
|
|
||||||
from zulint.custom_rules import Rule
|
|
||||||
|
|
||||||
whitespace_rules = [
|
|
||||||
# This linter should be first since bash_rules depends on it.
|
# This linter should be first since bash_rules depends on it.
|
||||||
{"pattern": r"\s+$", "strip": "\n", "description": "Fix trailing whitespace"},
|
{"pattern": r"\s+$", "strip": "\n", "description": "Fix trailing whitespace"},
|
||||||
{"pattern": "\t", "strip": "\n", "description": "Fix tab-based whitespace"},
|
{"pattern": "\t", "strip": "\n", "description": "Fix tab-based whitespace"},
|
||||||
] # type: List[Rule]
|
]
|
||||||
|
|
||||||
markdown_whitespace_rules = list(
|
markdown_whitespace_rules = list(
|
||||||
rule for rule in whitespace_rules if rule["pattern"] != r"\s+$"
|
rule for rule in whitespace_rules if rule["pattern"] != r"\s+$"
|
||||||
|
@ -129,7 +125,7 @@ json_rules = RuleList(
|
||||||
rules=whitespace_rules[0:1],
|
rules=whitespace_rules[0:1],
|
||||||
)
|
)
|
||||||
|
|
||||||
prose_style_rules = [
|
prose_style_rules: List[Rule] = [
|
||||||
{
|
{
|
||||||
"pattern": r'[^\/\#\-"]([jJ]avascript)', # exclude usage in hrefs/divs
|
"pattern": r'[^\/\#\-"]([jJ]avascript)', # exclude usage in hrefs/divs
|
||||||
"description": "javascript should be spelled JavaScript",
|
"description": "javascript should be spelled JavaScript",
|
||||||
|
@ -147,7 +143,7 @@ prose_style_rules = [
|
||||||
"pattern": r"[^-_]botserver(?!rc)|bot server",
|
"pattern": r"[^-_]botserver(?!rc)|bot server",
|
||||||
"description": "Use Botserver instead of botserver or Botserver.",
|
"description": "Use Botserver instead of botserver or Botserver.",
|
||||||
},
|
},
|
||||||
] # type: List[Rule]
|
]
|
||||||
|
|
||||||
markdown_docs_length_exclude = {
|
markdown_docs_length_exclude = {
|
||||||
"zulip_bots/zulip_bots/bots/converter/doc.md",
|
"zulip_bots/zulip_bots/bots/converter/doc.md",
|
||||||
|
|
10
tools/deploy
10
tools/deploy
|
@ -11,12 +11,12 @@ from typing import Any, Callable, Dict, List
|
||||||
import requests
|
import requests
|
||||||
from requests import Response
|
from requests import Response
|
||||||
|
|
||||||
red = "\033[91m" # type: str
|
red = "\033[91m"
|
||||||
green = "\033[92m" # type: str
|
green = "\033[92m"
|
||||||
end_format = "\033[0m" # type: str
|
end_format = "\033[0m"
|
||||||
bold = "\033[1m" # type: str
|
bold = "\033[1m"
|
||||||
|
|
||||||
bots_dir = ".bots" # type: str
|
bots_dir = ".bots"
|
||||||
|
|
||||||
|
|
||||||
def pack(options: argparse.Namespace) -> None:
|
def pack(options: argparse.Namespace) -> None:
|
||||||
|
|
|
@ -175,7 +175,7 @@ for inpath in force_include:
|
||||||
try:
|
try:
|
||||||
ext = os.path.splitext(inpath)[1].split(".")[1]
|
ext = os.path.splitext(inpath)[1].split(".")[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
ext = "py" # type: str
|
ext = "py"
|
||||||
files_dict[ext].append(inpath)
|
files_dict[ext].append(inpath)
|
||||||
|
|
||||||
pyi_files = set(files_dict["pyi"])
|
pyi_files = set(files_dict["pyi"])
|
||||||
|
|
|
@ -21,7 +21,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
|
||||||
nickserv_password: str = "",
|
nickserv_password: str = "",
|
||||||
port: int = 6667,
|
port: int = 6667,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.channel = channel # type: irc.bot.Channel
|
self.channel: irc.bot.Channel = channel
|
||||||
self.zulip_client = zulip_client
|
self.zulip_client = zulip_client
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
self.topic = topic
|
self.topic = topic
|
||||||
|
|
|
@ -8,9 +8,9 @@ from oauth2client.file import Storage
|
||||||
try:
|
try:
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
flags = argparse.ArgumentParser(
|
flags: Optional[argparse.Namespace] = argparse.ArgumentParser(
|
||||||
parents=[tools.argparser]
|
parents=[tools.argparser]
|
||||||
).parse_args() # type: Optional[argparse.Namespace]
|
).parse_args()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
flags = None
|
flags = None
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,10 @@ APPLICATION_NAME = "Zulip"
|
||||||
HOME_DIR = os.path.expanduser("~")
|
HOME_DIR = os.path.expanduser("~")
|
||||||
|
|
||||||
# Our cached view of the calendar, updated periodically.
|
# Our cached view of the calendar, updated periodically.
|
||||||
events = [] # type: List[Tuple[int, datetime.datetime, str]]
|
events: List[Tuple[int, datetime.datetime, str]] = []
|
||||||
|
|
||||||
# Unique keys for events we've already sent, so we don't remind twice.
|
# Unique keys for events we've already sent, so we don't remind twice.
|
||||||
sent = set() # type: Set[Tuple[int, datetime.datetime]]
|
sent: Set[Tuple[int, datetime.datetime]] = set()
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
sys.path.append(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class JabberToZulipBot(ClientXMPP):
|
||||||
self.nick = jid.username
|
self.nick = jid.username
|
||||||
jid.resource = "zulip"
|
jid.resource = "zulip"
|
||||||
ClientXMPP.__init__(self, jid, password)
|
ClientXMPP.__init__(self, jid, password)
|
||||||
self.rooms = set() # type: Set[str]
|
self.rooms: Set[str] = set()
|
||||||
self.rooms_to_join = rooms
|
self.rooms_to_join = rooms
|
||||||
self.add_event_handler("session_start", self.session_start)
|
self.add_event_handler("session_start", self.session_start)
|
||||||
self.add_event_handler("message", self.message)
|
self.add_event_handler("message", self.message)
|
||||||
|
@ -205,7 +205,7 @@ class JabberToZulipBot(ClientXMPP):
|
||||||
class ZulipToJabberBot:
|
class ZulipToJabberBot:
|
||||||
def __init__(self, zulip_client: Client) -> None:
|
def __init__(self, zulip_client: Client) -> None:
|
||||||
self.client = zulip_client
|
self.client = zulip_client
|
||||||
self.jabber = None # type: Optional[JabberToZulipBot]
|
self.jabber: Optional[JabberToZulipBot] = None
|
||||||
|
|
||||||
def set_jabber_client(self, client: JabberToZulipBot) -> None:
|
def set_jabber_client(self, client: JabberToZulipBot) -> None:
|
||||||
self.jabber = client
|
self.jabber = client
|
||||||
|
@ -282,7 +282,7 @@ def get_rooms(zulipToJabber: ZulipToJabberBot) -> List[str]:
|
||||||
else:
|
else:
|
||||||
stream_infos = get_stream_infos("subscriptions", zulipToJabber.client.get_subscriptions)
|
stream_infos = get_stream_infos("subscriptions", zulipToJabber.client.get_subscriptions)
|
||||||
|
|
||||||
rooms = [] # type: List[str]
|
rooms: List[str] = []
|
||||||
for stream_info in stream_infos:
|
for stream_info in stream_infos:
|
||||||
stream = stream_info["name"]
|
stream = stream_info["name"]
|
||||||
if stream.endswith("/xmpp"):
|
if stream.endswith("/xmpp"):
|
||||||
|
|
|
@ -105,7 +105,7 @@ def process_logs() -> None:
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = zulip.add_default_arguments(argparse.ArgumentParser()) # type: argparse.ArgumentParser
|
parser = zulip.add_default_arguments(argparse.ArgumentParser())
|
||||||
parser.add_argument("--control-path", default="/etc/log2zulip.conf")
|
parser.add_argument("--control-path", default="/etc/log2zulip.conf")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ VERSION = "0.9"
|
||||||
# Nagios passes the notification details as command line options.
|
# Nagios passes the notification details as command line options.
|
||||||
# In Nagios, "output" means "first line of output", and "long
|
# In Nagios, "output" means "first line of output", and "long
|
||||||
# output" means "other lines of output".
|
# output" means "other lines of output".
|
||||||
parser = zulip.add_default_arguments(argparse.ArgumentParser()) # type: argparse.ArgumentParser
|
parser = zulip.add_default_arguments(argparse.ArgumentParser())
|
||||||
parser.add_argument("--output", default="")
|
parser.add_argument("--output", default="")
|
||||||
parser.add_argument("--long-output", default="")
|
parser.add_argument("--long-output", default="")
|
||||||
parser.add_argument("--stream", default="nagios")
|
parser.add_argument("--stream", default="nagios")
|
||||||
|
@ -17,11 +17,9 @@ for opt in ("type", "host", "service", "state"):
|
||||||
parser.add_argument("--" + opt)
|
parser.add_argument("--" + opt)
|
||||||
opts = parser.parse_args()
|
opts = parser.parse_args()
|
||||||
|
|
||||||
client = zulip.Client(
|
client = zulip.Client(config_file=opts.config, client="ZulipNagios/" + VERSION)
|
||||||
config_file=opts.config, client="ZulipNagios/" + VERSION
|
|
||||||
) # type: zulip.Client
|
|
||||||
|
|
||||||
msg = dict(type="stream", to=opts.stream) # type: Dict[str, Any]
|
msg: Dict[str, Any] = dict(type="stream", to=opts.stream)
|
||||||
|
|
||||||
# Set a subject based on the host or service in question. This enables
|
# Set a subject based on the host or service in question. This enables
|
||||||
# threaded discussion of multiple concurrent issues, and provides useful
|
# threaded discussion of multiple concurrent issues, and provides useful
|
||||||
|
|
|
@ -52,7 +52,7 @@ def format_deployment_message(
|
||||||
|
|
||||||
## If properly installed, the Zulip API should be in your import
|
## If properly installed, the Zulip API should be in your import
|
||||||
## path, but if not, set a custom path below
|
## path, but if not, set a custom path below
|
||||||
ZULIP_API_PATH = None # type: Optional[str]
|
ZULIP_API_PATH: Optional[str] = None
|
||||||
|
|
||||||
# Set this to your Zulip server's API URI
|
# Set this to your Zulip server's API URI
|
||||||
ZULIP_SITE = "https://zulip.example.com"
|
ZULIP_SITE = "https://zulip.example.com"
|
||||||
|
|
|
@ -37,11 +37,11 @@ client = zulip.Client(
|
||||||
site=config.ZULIP_SITE,
|
site=config.ZULIP_SITE,
|
||||||
api_key=config.ZULIP_API_KEY,
|
api_key=config.ZULIP_API_KEY,
|
||||||
client="ZulipPerforce/" + __version__,
|
client="ZulipPerforce/" + __version__,
|
||||||
) # type: zulip.Client
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
changelist = int(sys.argv[1]) # type: int
|
changelist = int(sys.argv[1])
|
||||||
changeroot = sys.argv[2] # type: str
|
changeroot = sys.argv[2]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
print("Wrong number of arguments.\n\n", end=" ", file=sys.stderr)
|
print("Wrong number of arguments.\n\n", end=" ", file=sys.stderr)
|
||||||
print(__doc__, file=sys.stderr)
|
print(__doc__, file=sys.stderr)
|
||||||
|
@ -51,11 +51,9 @@ except ValueError:
|
||||||
print(__doc__, file=sys.stderr)
|
print(__doc__, file=sys.stderr)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
metadata = git_p4.p4_describe(changelist) # type: Dict[str, str]
|
metadata: Dict[str, str] = git_p4.p4_describe(changelist)
|
||||||
|
|
||||||
destination = config.commit_notice_destination(
|
destination: Optional[Dict[str, str]] = config.commit_notice_destination(changeroot, changelist)
|
||||||
changeroot, changelist
|
|
||||||
) # type: Optional[Dict[str, str]]
|
|
||||||
|
|
||||||
if destination is None:
|
if destination is None:
|
||||||
# Don't forward the notice anywhere
|
# Don't forward the notice anywhere
|
||||||
|
@ -88,12 +86,12 @@ message = """**{user}** committed revision @{change} to `{path}`.
|
||||||
```
|
```
|
||||||
""".format(
|
""".format(
|
||||||
user=metadata["user"], change=change, path=changeroot, desc=metadata["desc"]
|
user=metadata["user"], change=change, path=changeroot, desc=metadata["desc"]
|
||||||
) # type: str
|
)
|
||||||
|
|
||||||
message_data = {
|
message_data: Dict[str, Any] = {
|
||||||
"type": "stream",
|
"type": "stream",
|
||||||
"to": destination["stream"],
|
"to": destination["stream"],
|
||||||
"subject": destination["subject"],
|
"subject": destination["subject"],
|
||||||
"content": message,
|
"content": message,
|
||||||
} # type: Dict[str, Any]
|
}
|
||||||
client.send_message(message_data)
|
client.send_message(message_data)
|
||||||
|
|
|
@ -20,9 +20,9 @@ import feedparser
|
||||||
|
|
||||||
import zulip
|
import zulip
|
||||||
|
|
||||||
VERSION = "0.9" # type: str
|
VERSION = "0.9"
|
||||||
RSS_DATA_DIR = os.path.expanduser(os.path.join("~", ".cache", "zulip-rss")) # type: str
|
RSS_DATA_DIR = os.path.expanduser(os.path.join("~", ".cache", "zulip-rss"))
|
||||||
OLDNESS_THRESHOLD = 30 # type: int
|
OLDNESS_THRESHOLD = 30
|
||||||
|
|
||||||
usage = """Usage: Send summaries of RSS entries for your favorite feeds to Zulip.
|
usage = """Usage: Send summaries of RSS entries for your favorite feeds to Zulip.
|
||||||
|
|
||||||
|
@ -48,9 +48,7 @@ stream every 5 minutes is:
|
||||||
|
|
||||||
*/5 * * * * /usr/local/share/zulip/integrations/rss/rss-bot"""
|
*/5 * * * * /usr/local/share/zulip/integrations/rss/rss-bot"""
|
||||||
|
|
||||||
parser = zulip.add_default_arguments(
|
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage))
|
||||||
argparse.ArgumentParser(usage)
|
|
||||||
) # type: argparse.ArgumentParser
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--stream",
|
"--stream",
|
||||||
dest="stream",
|
dest="stream",
|
||||||
|
@ -94,7 +92,7 @@ parser.add_argument(
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
opts = parser.parse_args() # type: Any
|
opts = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def mkdir_p(path: str) -> None:
|
def mkdir_p(path: str) -> None:
|
||||||
|
@ -115,15 +113,15 @@ except OSError:
|
||||||
print(f"Unable to store RSS data at {opts.data_dir}.", file=sys.stderr)
|
print(f"Unable to store RSS data at {opts.data_dir}.", file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
log_file = os.path.join(opts.data_dir, "rss-bot.log") # type: str
|
log_file = os.path.join(opts.data_dir, "rss-bot.log")
|
||||||
log_format = "%(asctime)s: %(message)s" # type: str
|
log_format = "%(asctime)s: %(message)s"
|
||||||
logging.basicConfig(format=log_format)
|
logging.basicConfig(format=log_format)
|
||||||
|
|
||||||
formatter = logging.Formatter(log_format) # type: logging.Formatter
|
formatter = logging.Formatter(log_format)
|
||||||
file_handler = logging.FileHandler(log_file) # type: logging.FileHandler
|
file_handler = logging.FileHandler(log_file)
|
||||||
file_handler.setFormatter(formatter)
|
file_handler.setFormatter(formatter)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__) # type: logging.Logger
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
@ -138,7 +136,7 @@ class MLStripper(HTMLParser):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.reset()
|
self.reset()
|
||||||
self.fed = [] # type: List[str]
|
self.fed: List[str] = []
|
||||||
|
|
||||||
def handle_data(self, data: str) -> None:
|
def handle_data(self, data: str) -> None:
|
||||||
self.fed.append(data)
|
self.fed.append(data)
|
||||||
|
@ -173,7 +171,7 @@ def elide_subject(subject: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def send_zulip(entry: Any, feed_name: str) -> Dict[str, Any]:
|
def send_zulip(entry: Any, feed_name: str) -> Dict[str, Any]:
|
||||||
body = entry.summary # type: str
|
body: str = entry.summary
|
||||||
if opts.unwrap:
|
if opts.unwrap:
|
||||||
body = unwrap_text(body)
|
body = unwrap_text(body)
|
||||||
|
|
||||||
|
@ -182,56 +180,52 @@ def send_zulip(entry: Any, feed_name: str) -> Dict[str, Any]:
|
||||||
entry.link,
|
entry.link,
|
||||||
strip_tags(body),
|
strip_tags(body),
|
||||||
entry.link,
|
entry.link,
|
||||||
) # type: str
|
)
|
||||||
|
|
||||||
if opts.math:
|
if opts.math:
|
||||||
content = content.replace("$", "$$")
|
content = content.replace("$", "$$")
|
||||||
|
|
||||||
message = {
|
message: Dict[str, str] = {
|
||||||
"type": "stream",
|
"type": "stream",
|
||||||
"to": opts.stream,
|
"to": opts.stream,
|
||||||
"subject": opts.topic or elide_subject(feed_name),
|
"subject": opts.topic or elide_subject(feed_name),
|
||||||
"content": content,
|
"content": content,
|
||||||
} # type: Dict[str, str]
|
}
|
||||||
return client.send_message(message)
|
return client.send_message(message)
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(opts.feed_file) as f:
|
with open(opts.feed_file) as f:
|
||||||
feed_urls = [feed.strip() for feed in f.readlines()] # type: List[str]
|
feed_urls: List[str] = [feed.strip() for feed in f.readlines()]
|
||||||
except OSError:
|
except OSError:
|
||||||
log_error_and_exit(f"Unable to read feed file at {opts.feed_file}.")
|
log_error_and_exit(f"Unable to read feed file at {opts.feed_file}.")
|
||||||
|
|
||||||
client = zulip.Client(
|
client: zulip.Client = zulip.Client(
|
||||||
email=opts.zulip_email,
|
email=opts.zulip_email,
|
||||||
api_key=opts.zulip_api_key,
|
api_key=opts.zulip_api_key,
|
||||||
config_file=opts.zulip_config_file,
|
config_file=opts.zulip_config_file,
|
||||||
site=opts.zulip_site,
|
site=opts.zulip_site,
|
||||||
client="ZulipRSS/" + VERSION,
|
client="ZulipRSS/" + VERSION,
|
||||||
) # type: zulip.Client
|
)
|
||||||
|
|
||||||
first_message = True # type: bool
|
first_message = True
|
||||||
|
|
||||||
for feed_url in feed_urls:
|
for feed_url in feed_urls:
|
||||||
feed_file = os.path.join(opts.data_dir, urllib.parse.urlparse(feed_url).netloc) # Type: str
|
feed_file = os.path.join(opts.data_dir, urllib.parse.urlparse(feed_url).netloc) # Type: str
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(feed_file) as f:
|
with open(feed_file) as f:
|
||||||
old_feed_hashes = {
|
old_feed_hashes = {line.strip(): True for line in f.readlines()}
|
||||||
line.strip(): True for line in f.readlines()
|
|
||||||
} # type: Dict[str, bool]
|
|
||||||
except OSError:
|
except OSError:
|
||||||
old_feed_hashes = {}
|
old_feed_hashes = {}
|
||||||
|
|
||||||
new_hashes = [] # type: List[str]
|
new_hashes: List[str] = []
|
||||||
data = feedparser.parse(feed_url) # type: feedparser.parse
|
data = feedparser.parse(feed_url)
|
||||||
|
|
||||||
for entry in data.entries:
|
for entry in data.entries:
|
||||||
entry_hash = compute_entry_hash(entry) # type: str
|
entry_hash = compute_entry_hash(entry)
|
||||||
# An entry has either been published or updated.
|
# An entry has either been published or updated.
|
||||||
entry_time = entry.get(
|
entry_time: Tuple[int, int] = entry.get("published_parsed", entry.get("updated_parsed"))
|
||||||
"published_parsed", entry.get("updated_parsed")
|
|
||||||
) # type: Tuple[int, int]
|
|
||||||
if (
|
if (
|
||||||
entry_time is not None
|
entry_time is not None
|
||||||
and (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24
|
and (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24
|
||||||
|
@ -247,9 +241,9 @@ for feed_url in feed_urls:
|
||||||
# entries in reverse chronological order.
|
# entries in reverse chronological order.
|
||||||
break
|
break
|
||||||
|
|
||||||
feed_name = data.feed.title or feed_url # type: str
|
feed_name: str = data.feed.title or feed_url
|
||||||
|
|
||||||
response = send_zulip(entry, feed_name) # type: Dict[str, Any]
|
response: Dict[str, Any] = send_zulip(entry, feed_name)
|
||||||
if response["result"] != "success":
|
if response["result"] != "success":
|
||||||
logger.error(f"Error processing {feed_url}")
|
logger.error(f"Error processing {feed_url}")
|
||||||
logger.error(str(response))
|
logger.error(str(response))
|
||||||
|
|
|
@ -31,17 +31,17 @@ client = zulip.Client(
|
||||||
site=config.ZULIP_SITE,
|
site=config.ZULIP_SITE,
|
||||||
api_key=config.ZULIP_API_KEY,
|
api_key=config.ZULIP_API_KEY,
|
||||||
client="ZulipSVN/" + VERSION,
|
client="ZulipSVN/" + VERSION,
|
||||||
) # type: zulip.Client
|
)
|
||||||
svn = pysvn.Client() # type: pysvn.Client
|
svn = pysvn.Client()
|
||||||
|
|
||||||
path, rev = sys.argv[1:]
|
path, rev = sys.argv[1:]
|
||||||
|
|
||||||
# since its a local path, prepend "file://"
|
# since its a local path, prepend "file://"
|
||||||
path = "file://" + path
|
path = "file://" + path
|
||||||
|
|
||||||
entry = svn.log(path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev))[
|
entry: Dict[str, Any] = svn.log(
|
||||||
0
|
path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev)
|
||||||
] # type: Dict[str, Any]
|
)[0]
|
||||||
message = "**{}** committed revision r{} to `{}`.\n\n> {}".format(
|
message = "**{}** committed revision r{} to `{}`.\n\n> {}".format(
|
||||||
entry["author"], rev, path.split("/")[-1], entry["revprops"]["svn:log"]
|
entry["author"], rev, path.split("/")[-1], entry["revprops"]["svn:log"]
|
||||||
)
|
)
|
||||||
|
@ -49,10 +49,10 @@ message = "**{}** committed revision r{} to `{}`.\n\n> {}".format(
|
||||||
destination = config.commit_notice_destination(path, rev)
|
destination = config.commit_notice_destination(path, rev)
|
||||||
|
|
||||||
if destination is not None:
|
if destination is not None:
|
||||||
message_data = {
|
message_data: Dict[str, Any] = {
|
||||||
"type": "stream",
|
"type": "stream",
|
||||||
"to": destination["stream"],
|
"to": destination["stream"],
|
||||||
"subject": destination["subject"],
|
"subject": destination["subject"],
|
||||||
"content": message,
|
"content": message,
|
||||||
} # type: Dict[str, Any]
|
}
|
||||||
client.send_message(message_data)
|
client.send_message(message_data)
|
||||||
|
|
|
@ -192,8 +192,8 @@ if not actually_subscribed:
|
||||||
print_status_and_exit(1)
|
print_status_and_exit(1)
|
||||||
|
|
||||||
# Prepare keys
|
# Prepare keys
|
||||||
zhkeys = {} # type: Dict[str, Tuple[str, str]]
|
zhkeys: Dict[str, Tuple[str, str]] = {}
|
||||||
hzkeys = {} # type: Dict[str, Tuple[str, str]]
|
hzkeys: Dict[str, Tuple[str, str]] = {}
|
||||||
|
|
||||||
|
|
||||||
def gen_key(key_dict: Dict[str, Tuple[str, str]]) -> str:
|
def gen_key(key_dict: Dict[str, Tuple[str, str]]) -> str:
|
||||||
|
@ -313,7 +313,7 @@ def process_keys(content_list: List[str]) -> Tuple[Dict[str, int], Set[str], Set
|
||||||
# Start by filtering out any keys that might have come from
|
# Start by filtering out any keys that might have come from
|
||||||
# concurrent check-mirroring processes
|
# concurrent check-mirroring processes
|
||||||
content_keys = [key for key in content_list if key in all_keys]
|
content_keys = [key for key in content_list if key in all_keys]
|
||||||
key_counts = {} # type: Dict[str, int]
|
key_counts: Dict[str, int] = {}
|
||||||
for key in all_keys:
|
for key in all_keys:
|
||||||
key_counts[key] = 0
|
key_counts[key] = 0
|
||||||
for key in content_keys:
|
for key in content_keys:
|
||||||
|
|
|
@ -1107,7 +1107,7 @@ def valid_stream_name(name: str) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def parse_zephyr_subs(verbose: bool = False) -> 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]]
|
zephyr_subscriptions: Set[Tuple[str, str, str]] = set()
|
||||||
subs_file = os.path.join(os.environ["HOME"], ".zephyr.subs")
|
subs_file = os.path.join(os.environ["HOME"], ".zephyr.subs")
|
||||||
if not os.path.exists(subs_file):
|
if not os.path.exists(subs_file):
|
||||||
if verbose:
|
if verbose:
|
||||||
|
@ -1348,7 +1348,7 @@ or specify the --api-key-file option."""
|
||||||
options.session_path = f"/var/tmp/{options.user}"
|
options.session_path = f"/var/tmp/{options.user}"
|
||||||
|
|
||||||
if options.forward_from_zulip:
|
if options.forward_from_zulip:
|
||||||
child_pid = os.fork() # type: Optional[int]
|
child_pid: Optional[int] = os.fork()
|
||||||
if child_pid == 0:
|
if child_pid == 0:
|
||||||
CURRENT_STATE = States.ZulipToZephyr
|
CURRENT_STATE = States.ZulipToZephyr
|
||||||
# Run the zulip => zephyr mirror in the child
|
# Run the zulip => zephyr mirror in the child
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import pkgutil
|
import pkgutil
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
__path__ = pkgutil.extend_path(__path__, __name__) # type: List[str]
|
__path__: List[str] = pkgutil.extend_path(__path__, __name__)
|
||||||
|
|
|
@ -485,7 +485,7 @@ class Client:
|
||||||
"certificate will not be validated, making the "
|
"certificate will not be validated, making the "
|
||||||
"HTTPS connection potentially insecure"
|
"HTTPS connection potentially insecure"
|
||||||
)
|
)
|
||||||
self.tls_verification = False # type: Union[bool, str]
|
self.tls_verification: Union[bool, str] = False
|
||||||
elif cert_bundle is not None:
|
elif cert_bundle is not None:
|
||||||
if not os.path.isfile(cert_bundle):
|
if not os.path.isfile(cert_bundle):
|
||||||
raise ConfigNotFoundError(f"tls bundle '{cert_bundle}' does not exist")
|
raise ConfigNotFoundError(f"tls bundle '{cert_bundle}' does not exist")
|
||||||
|
@ -509,7 +509,7 @@ class Client:
|
||||||
self.client_cert = client_cert
|
self.client_cert = client_cert
|
||||||
self.client_cert_key = client_cert_key
|
self.client_cert_key = client_cert_key
|
||||||
|
|
||||||
self.session = None # type: Optional[requests.Session]
|
self.session: Optional[requests.Session] = None
|
||||||
|
|
||||||
self.has_connected = False
|
self.has_connected = False
|
||||||
|
|
||||||
|
@ -527,10 +527,10 @@ class Client:
|
||||||
# Build a client cert object for requests
|
# Build a client cert object for requests
|
||||||
if self.client_cert_key is not None:
|
if self.client_cert_key is not None:
|
||||||
assert self.client_cert is not None # Otherwise ZulipError near end of __init__
|
assert self.client_cert is not None # Otherwise ZulipError near end of __init__
|
||||||
client_cert = (
|
client_cert: Union[None, str, Tuple[str, str]] = (
|
||||||
self.client_cert,
|
self.client_cert,
|
||||||
self.client_cert_key,
|
self.client_cert_key,
|
||||||
) # type: Union[None, str, Tuple[str, str]]
|
)
|
||||||
else:
|
else:
|
||||||
client_cert = self.client_cert
|
client_cert = self.client_cert
|
||||||
|
|
||||||
|
@ -602,11 +602,11 @@ class Client:
|
||||||
self.ensure_session()
|
self.ensure_session()
|
||||||
assert self.session is not None
|
assert self.session is not None
|
||||||
|
|
||||||
query_state = {
|
query_state: Dict[str, Any] = {
|
||||||
"had_error_retry": False,
|
"had_error_retry": False,
|
||||||
"request": request,
|
"request": request,
|
||||||
"failures": 0,
|
"failures": 0,
|
||||||
} # type: Dict[str, Any]
|
}
|
||||||
|
|
||||||
def error_retry(error_string: str) -> bool:
|
def error_retry(error_string: str) -> bool:
|
||||||
if not self.retry_on_errors or query_state["failures"] >= 10:
|
if not self.retry_on_errors or query_state["failures"] >= 10:
|
||||||
|
|
|
@ -40,7 +40,7 @@ request = {
|
||||||
"apply_markdown": False,
|
"apply_markdown": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
all_messages = [] # type: List[Dict[str, Any]]
|
all_messages: List[Dict[str, Any]] = []
|
||||||
found_newest = False
|
found_newest = False
|
||||||
|
|
||||||
while not found_newest:
|
while not found_newest:
|
||||||
|
|
|
@ -28,7 +28,7 @@ options = parser.parse_args()
|
||||||
client = zulip.init_from_options(options)
|
client = zulip.init_from_options(options)
|
||||||
|
|
||||||
if options.file_path:
|
if options.file_path:
|
||||||
file = open(options.file_path, "rb") # type: IO[Any]
|
file: IO[Any] = open(options.file_path, "rb")
|
||||||
else:
|
else:
|
||||||
file = StringIO("This is a test file.")
|
file = StringIO("This is a test file.")
|
||||||
file.name = "test.txt"
|
file.name = "test.txt"
|
||||||
|
|
|
@ -241,14 +241,14 @@ class BaremetricsHandler:
|
||||||
return "\n".join(response)
|
return "\n".join(response)
|
||||||
|
|
||||||
def create_plan(self, parameters: List[str]) -> str:
|
def create_plan(self, parameters: List[str]) -> str:
|
||||||
data_header = {
|
data_header: Any = {
|
||||||
"oid": parameters[1],
|
"oid": parameters[1],
|
||||||
"name": parameters[2],
|
"name": parameters[2],
|
||||||
"currency": parameters[3],
|
"currency": parameters[3],
|
||||||
"amount": int(parameters[4]),
|
"amount": int(parameters[4]),
|
||||||
"interval": parameters[5],
|
"interval": parameters[5],
|
||||||
"interval_count": int(parameters[6]),
|
"interval_count": int(parameters[6]),
|
||||||
} # type: Any
|
}
|
||||||
|
|
||||||
url = f"https://api.baremetrics.com/v1/{parameters[0]}/plans"
|
url = f"https://api.baremetrics.com/v1/{parameters[0]}/plans"
|
||||||
create_plan_response = requests.post(url, data=data_header, headers=self.auth_header)
|
create_plan_response = requests.post(url, data=data_header, headers=self.auth_header)
|
||||||
|
|
|
@ -87,8 +87,8 @@ def get_bot_converter_response(message: Dict[str, str], bot_handler: BotHandler)
|
||||||
exponent -= exp
|
exponent -= exp
|
||||||
unit_to = unit_to[len(key) :]
|
unit_to = unit_to[len(key) :]
|
||||||
|
|
||||||
uf_to_std = utils.UNITS.get(unit_from, []) # type: List[Any]
|
uf_to_std: List[Any] = utils.UNITS.get(unit_from, [])
|
||||||
ut_to_std = utils.UNITS.get(unit_to, []) # type: List[Any]
|
ut_to_std: List[Any] = utils.UNITS.get(unit_to, [])
|
||||||
|
|
||||||
if not uf_to_std:
|
if not uf_to_std:
|
||||||
results.append("`" + unit_from + "` is not a valid unit. " + utils.QUICK_HELP)
|
results.append("`" + unit_from + "` is not a valid unit. " + utils.QUICK_HELP)
|
||||||
|
|
|
@ -148,7 +148,7 @@ def dbx_ls(client: Any, fn: str) -> str:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = client.files_list_folder(fn)
|
result = client.files_list_folder(fn)
|
||||||
files_list = [] # type: List[str]
|
files_list: List[str] = []
|
||||||
for meta in result.entries:
|
for meta in result.entries:
|
||||||
files_list += [" - " + URL.format(name=meta.name, path=meta.path_lower)]
|
files_list += [" - " + URL.format(name=meta.name, path=meta.path_lower)]
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,10 @@ class HelloWorldHandler:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None:
|
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None:
|
||||||
content = "beep boop" # type: str
|
content = "beep boop"
|
||||||
bot_handler.send_reply(message, content)
|
bot_handler.send_reply(message, content)
|
||||||
|
|
||||||
emoji_name = "wave" # type: str
|
emoji_name = "wave"
|
||||||
bot_handler.react(message, emoji_name)
|
bot_handler.react(message, emoji_name)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from zulip_bots.test_lib import BotTestCase, DefaultTests
|
||||||
|
|
||||||
|
|
||||||
class TestHelpBot(BotTestCase, DefaultTests):
|
class TestHelpBot(BotTestCase, DefaultTests):
|
||||||
bot_name = "helloworld" # type: str
|
bot_name: str = "helloworld"
|
||||||
|
|
||||||
def test_bot(self) -> None:
|
def test_bot(self) -> None:
|
||||||
dialog = [
|
dialog = [
|
||||||
|
|
|
@ -4,7 +4,7 @@ from zulip_bots.test_lib import BotTestCase, DefaultTests
|
||||||
|
|
||||||
|
|
||||||
class TestIDoneThisBot(BotTestCase, DefaultTests):
|
class TestIDoneThisBot(BotTestCase, DefaultTests):
|
||||||
bot_name = "idonethis" # type: str
|
bot_name: str = "idonethis"
|
||||||
|
|
||||||
def test_create_entry_default_team(self) -> None:
|
def test_create_entry_default_team(self) -> None:
|
||||||
with self.mock_config_info(
|
with self.mock_config_info(
|
||||||
|
|
|
@ -23,7 +23,7 @@ class LinkShortenerHandler:
|
||||||
self.check_api_key(bot_handler)
|
self.check_api_key(bot_handler)
|
||||||
|
|
||||||
def check_api_key(self, bot_handler: BotHandler) -> None:
|
def check_api_key(self, bot_handler: BotHandler) -> None:
|
||||||
test_request_data = self.call_link_shorten_service("www.youtube.com/watch") # type: Any
|
test_request_data: Any = self.call_link_shorten_service("www.youtube.com/watch")
|
||||||
try:
|
try:
|
||||||
if self.is_invalid_token_error(test_request_data):
|
if self.is_invalid_token_error(test_request_data):
|
||||||
bot_handler.quit(
|
bot_handler.quit(
|
||||||
|
|
|
@ -75,12 +75,12 @@ class MentionHandler:
|
||||||
"Accept-Version": "1.15",
|
"Accept-Version": "1.15",
|
||||||
}
|
}
|
||||||
|
|
||||||
create_alert_data = {
|
create_alert_data: Any = {
|
||||||
"name": keyword,
|
"name": keyword,
|
||||||
"query": {"type": "basic", "included_keywords": [keyword]},
|
"query": {"type": "basic", "included_keywords": [keyword]},
|
||||||
"languages": ["en"],
|
"languages": ["en"],
|
||||||
"sources": ["web"],
|
"sources": ["web"],
|
||||||
} # type: Any
|
}
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
"https://api.mention.net/api/accounts/" + self.account_id + "/alerts",
|
"https://api.mention.net/api/accounts/" + self.account_id + "/alerts",
|
||||||
|
|
|
@ -78,7 +78,7 @@ def query_salesforce(
|
||||||
) -> str:
|
) -> str:
|
||||||
arg = arg.strip()
|
arg = arg.strip()
|
||||||
qarg = arg.split(" -", 1)[0]
|
qarg = arg.split(" -", 1)[0]
|
||||||
split_args = [] # type: List[str]
|
split_args: List[str] = []
|
||||||
raw_arg = ""
|
raw_arg = ""
|
||||||
if len(arg.split(" -", 1)) > 1:
|
if len(arg.split(" -", 1)) > 1:
|
||||||
raw_arg = " -" + arg.split(" -", 1)[1]
|
raw_arg = " -" + arg.split(" -", 1)[1]
|
||||||
|
@ -96,10 +96,10 @@ def query_salesforce(
|
||||||
res = salesforce.query(
|
res = salesforce.query(
|
||||||
query.format(object_type["fields"], object_type["table"], qarg, limit_num)
|
query.format(object_type["fields"], object_type["table"], qarg, limit_num)
|
||||||
)
|
)
|
||||||
exclude_keys = [] # type: List[str]
|
exclude_keys: List[str] = []
|
||||||
if "exclude_keys" in command.keys():
|
if "exclude_keys" in command.keys():
|
||||||
exclude_keys = command["exclude_keys"]
|
exclude_keys = command["exclude_keys"]
|
||||||
force_keys = [] # type: List[str]
|
force_keys: List[str] = []
|
||||||
if "force_keys" in command.keys():
|
if "force_keys" in command.keys():
|
||||||
force_keys = command["force_keys"]
|
force_keys = command["force_keys"]
|
||||||
rank_output = False
|
rank_output = False
|
||||||
|
|
|
@ -96,7 +96,7 @@ mock_object_types = {
|
||||||
|
|
||||||
|
|
||||||
class TestSalesforceBot(BotTestCase, DefaultTests):
|
class TestSalesforceBot(BotTestCase, DefaultTests):
|
||||||
bot_name = "salesforce" # type: str
|
bot_name: str = "salesforce"
|
||||||
|
|
||||||
def _test(self, test_name: str, message: str, response: str, auth_success: bool = True) -> None:
|
def _test(self, test_name: str, message: str, response: str, auth_success: bool = True) -> None:
|
||||||
with self.mock_config_info(mock_config), mock_salesforce_auth(
|
with self.mock_config_info(mock_config), mock_salesforce_auth(
|
||||||
|
|
|
@ -3,7 +3,7 @@ from typing import Any, Dict, List
|
||||||
link_query = "SELECT {} FROM {} WHERE Id='{}'"
|
link_query = "SELECT {} FROM {} WHERE Id='{}'"
|
||||||
default_query = "SELECT {} FROM {} WHERE Name LIKE '%{}%' LIMIT {}"
|
default_query = "SELECT {} FROM {} WHERE Name LIKE '%{}%' LIMIT {}"
|
||||||
|
|
||||||
commands = [
|
commands: List[Dict[str, Any]] = [
|
||||||
{
|
{
|
||||||
"commands": ["search account", "find account", "search accounts", "find accounts"],
|
"commands": ["search account", "find account", "search accounts", "find accounts"],
|
||||||
"object": "account",
|
"object": "account",
|
||||||
|
@ -41,9 +41,9 @@ commands = [
|
||||||
"rank_output": True,
|
"rank_output": True,
|
||||||
"force_keys": ["Amount"],
|
"force_keys": ["Amount"],
|
||||||
},
|
},
|
||||||
] # type: List[Dict[str, Any]]
|
]
|
||||||
|
|
||||||
object_types = {
|
object_types: Dict[str, Dict[str, str]] = {
|
||||||
"account": {
|
"account": {
|
||||||
"fields": "Id, Name, Phone, BillingStreet, BillingCity, BillingState",
|
"fields": "Id, Name, Phone, BillingStreet, BillingCity, BillingState",
|
||||||
"table": "Account",
|
"table": "Account",
|
||||||
|
@ -53,4 +53,4 @@ object_types = {
|
||||||
"fields": "Id, Name, Amount, Probability, StageName, CloseDate",
|
"fields": "Id, Name, Amount, Probability, StageName, CloseDate",
|
||||||
"table": "Opportunity",
|
"table": "Opportunity",
|
||||||
},
|
},
|
||||||
} # type: Dict[str, Dict[str, str]]
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ class TicTacToeModel:
|
||||||
# there are two blanks and an 2 in each row, column, and diagonal (done in two_blanks).
|
# there are two blanks and an 2 in each row, column, and diagonal (done in two_blanks).
|
||||||
# If smarter is False, all blank locations can be chosen.
|
# If smarter is False, all blank locations can be chosen.
|
||||||
if self.smarter:
|
if self.smarter:
|
||||||
blanks = [] # type: Any
|
blanks: Any = []
|
||||||
for triplet in self.triplets:
|
for triplet in self.triplets:
|
||||||
result = self.two_blanks(triplet, board)
|
result = self.two_blanks(triplet, board)
|
||||||
if result:
|
if result:
|
||||||
|
|
|
@ -7,7 +7,7 @@ mock_config = {"api_key": "TEST", "access_token": "TEST", "user_name": "TEST"}
|
||||||
|
|
||||||
|
|
||||||
class TestTrelloBot(BotTestCase, DefaultTests):
|
class TestTrelloBot(BotTestCase, DefaultTests):
|
||||||
bot_name = "trello" # type: str
|
bot_name: str = "trello"
|
||||||
|
|
||||||
def test_bot_responds_to_empty_message(self) -> None:
|
def test_bot_responds_to_empty_message(self) -> None:
|
||||||
with self.mock_config_info(mock_config), patch("requests.get"):
|
with self.mock_config_info(mock_config), patch("requests.get"):
|
||||||
|
|
|
@ -93,7 +93,7 @@ class TrelloHandler:
|
||||||
return bot_response
|
return bot_response
|
||||||
|
|
||||||
def get_board_descs(self, boards: List[str]) -> str:
|
def get_board_descs(self, boards: List[str]) -> str:
|
||||||
bot_response = [] # type: List[str]
|
bot_response: List[str] = []
|
||||||
get_board_desc_url = "https://api.trello.com/1/boards/{}/"
|
get_board_desc_url = "https://api.trello.com/1/boards/{}/"
|
||||||
for index, board in enumerate(boards):
|
for index, board in enumerate(boards):
|
||||||
board_desc_response = requests.get(
|
board_desc_response = requests.get(
|
||||||
|
|
|
@ -15,7 +15,7 @@ from zulip_bots.test_lib import BotTestCase, DefaultTests, StubBotHandler, read_
|
||||||
|
|
||||||
|
|
||||||
class TestTriviaQuizBot(BotTestCase, DefaultTests):
|
class TestTriviaQuizBot(BotTestCase, DefaultTests):
|
||||||
bot_name = "trivia_quiz" # type: str
|
bot_name: str = "trivia_quiz"
|
||||||
|
|
||||||
new_question_response = (
|
new_question_response = (
|
||||||
"\nQ: Which class of animals are newts members of?\n\n"
|
"\nQ: Which class of animals are newts members of?\n\n"
|
||||||
|
|
|
@ -130,13 +130,13 @@ def get_quiz_from_payload(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
answers[letters[i + 1]] = result["incorrect_answers"][i]
|
answers[letters[i + 1]] = result["incorrect_answers"][i]
|
||||||
answers = {letter: fix_quotes(answer) for letter, answer in answers.items()}
|
answers = {letter: fix_quotes(answer) for letter, answer in answers.items()}
|
||||||
quiz = dict(
|
quiz: Dict[str, Any] = dict(
|
||||||
question=fix_quotes(question),
|
question=fix_quotes(question),
|
||||||
answers=answers,
|
answers=answers,
|
||||||
answered_options=[],
|
answered_options=[],
|
||||||
pending=True,
|
pending=True,
|
||||||
correct_letter=correct_letter,
|
correct_letter=correct_letter,
|
||||||
) # type: Dict[str, Any]
|
)
|
||||||
return quiz
|
return quiz
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@ from zulip_bots.test_lib import BotTestCase, DefaultTests, StubBotHandler, get_b
|
||||||
|
|
||||||
class TestYoutubeBot(BotTestCase, DefaultTests):
|
class TestYoutubeBot(BotTestCase, DefaultTests):
|
||||||
bot_name = "youtube"
|
bot_name = "youtube"
|
||||||
normal_config = {
|
normal_config: Dict[str, str] = {
|
||||||
"key": "12345678",
|
"key": "12345678",
|
||||||
"number_of_results": "5",
|
"number_of_results": "5",
|
||||||
"video_region": "US",
|
"video_region": "US",
|
||||||
} # type: Dict[str,str]
|
}
|
||||||
|
|
||||||
help_content = (
|
help_content = (
|
||||||
"*Help for YouTube bot* :robot_face: : \n\n"
|
"*Help for YouTube bot* :robot_face: : \n\n"
|
||||||
|
|
|
@ -56,7 +56,7 @@ class YoutubeHandler:
|
||||||
|
|
||||||
def search_youtube(query: str, key: str, region: str, max_results: int = 1) -> List[List[str]]:
|
def search_youtube(query: str, key: str, region: str, max_results: int = 1) -> List[List[str]]:
|
||||||
videos = []
|
videos = []
|
||||||
params = {
|
params: Dict[str, Union[str, int]] = {
|
||||||
"part": "id,snippet",
|
"part": "id,snippet",
|
||||||
"maxResults": max_results,
|
"maxResults": max_results,
|
||||||
"key": key,
|
"key": key,
|
||||||
|
@ -64,7 +64,7 @@ def search_youtube(query: str, key: str, region: str, max_results: int = 1) -> L
|
||||||
"alt": "json",
|
"alt": "json",
|
||||||
"type": "video",
|
"type": "video",
|
||||||
"regionCode": region,
|
"regionCode": region,
|
||||||
} # type: Dict[str, Union[str, int]]
|
}
|
||||||
|
|
||||||
url = "https://www.googleapis.com/youtube/v3/search"
|
url = "https://www.googleapis.com/youtube/v3/search"
|
||||||
try:
|
try:
|
||||||
|
@ -98,7 +98,7 @@ def get_bot_response(
|
||||||
key = config_info["key"]
|
key = config_info["key"]
|
||||||
max_results = int(config_info["number_of_results"])
|
max_results = int(config_info["number_of_results"])
|
||||||
region = config_info["video_region"]
|
region = config_info["video_region"]
|
||||||
video_list = [] # type: List[List[str]]
|
video_list: List[List[str]] = []
|
||||||
try:
|
try:
|
||||||
if query == "" or query is None:
|
if query == "" or query is None:
|
||||||
return YoutubeHandler.help_content
|
return YoutubeHandler.help_content
|
||||||
|
|
|
@ -55,17 +55,17 @@ class GameAdapter:
|
||||||
self.is_single_player = self.min_players == self.max_players == 1
|
self.is_single_player = self.min_players == self.max_players == 1
|
||||||
self.supports_computer = supports_computer
|
self.supports_computer = supports_computer
|
||||||
self.gameMessageHandler = gameMessageHandler()
|
self.gameMessageHandler = gameMessageHandler()
|
||||||
self.invites = {} # type: Dict[str, Dict[str, str]]
|
self.invites: Dict[str, Dict[str, str]] = {}
|
||||||
self.instances = {} # type: Dict[str, Any]
|
self.instances: Dict[str, Any] = {}
|
||||||
self.user_cache = {} # type: Dict[str, Dict[str, Any]]
|
self.user_cache: Dict[str, Dict[str, Any]] = {}
|
||||||
self.pending_subject_changes = [] # type: List[str]
|
self.pending_subject_changes: List[str] = []
|
||||||
self.stream = "games"
|
self.stream = "games"
|
||||||
self.rules = rules
|
self.rules = rules
|
||||||
|
|
||||||
# Values are [won, lost, drawn, total] new values can be added, but MUST be added to the end of the list.
|
# Values are [won, lost, drawn, total] new values can be added, but MUST be added to the end of the list.
|
||||||
def add_user_statistics(self, user: str, values: Dict[str, int]) -> None:
|
def add_user_statistics(self, user: str, values: Dict[str, int]) -> None:
|
||||||
self.get_user_cache()
|
self.get_user_cache()
|
||||||
current_values = {} # type: Dict[str, int]
|
current_values: Dict[str, int] = {}
|
||||||
if "stats" in self.get_user_by_email(user).keys():
|
if "stats" in self.get_user_by_email(user).keys():
|
||||||
current_values = self.user_cache[user]["stats"]
|
current_values = self.user_cache[user]["stats"]
|
||||||
for key, value in values.items():
|
for key, value in values.items():
|
||||||
|
@ -570,7 +570,7 @@ class GameAdapter:
|
||||||
|
|
||||||
def get_players(self, game_id: str, parameter: str = "a") -> List[str]:
|
def get_players(self, game_id: str, parameter: str = "a") -> List[str]:
|
||||||
if game_id in self.invites.keys():
|
if game_id in self.invites.keys():
|
||||||
players = [] # type: List[str]
|
players: List[str] = []
|
||||||
if (
|
if (
|
||||||
self.invites[game_id]["subject"] == "###private###" and "p" in parameter
|
self.invites[game_id]["subject"] == "###private###" and "p" in parameter
|
||||||
) or "p" not in parameter:
|
) or "p" not in parameter:
|
||||||
|
@ -587,7 +587,7 @@ class GameAdapter:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def get_game_info(self, game_id: str) -> Dict[str, Any]:
|
def get_game_info(self, game_id: str) -> Dict[str, Any]:
|
||||||
game_info = {} # type: Dict[str, Any]
|
game_info: Dict[str, Any] = {}
|
||||||
if game_id in self.instances.keys():
|
if game_id in self.instances.keys():
|
||||||
instance = self.instances[game_id]
|
instance = self.instances[game_id]
|
||||||
game_info = {
|
game_info = {
|
||||||
|
@ -855,8 +855,8 @@ class GameInstance:
|
||||||
self.model = deepcopy(self.gameAdapter.model())
|
self.model = deepcopy(self.gameAdapter.model())
|
||||||
self.board = self.model.current_board
|
self.board = self.model.current_board
|
||||||
self.turn = random.randrange(0, len(players)) - 1
|
self.turn = random.randrange(0, len(players)) - 1
|
||||||
self.current_draw = {} # type: Dict[str, bool]
|
self.current_draw: Dict[str, bool] = {}
|
||||||
self.current_messages = [] # type: List[str]
|
self.current_messages: List[str] = []
|
||||||
self.is_changing_subject = False
|
self.is_changing_subject = False
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
|
|
|
@ -53,7 +53,7 @@ class RateLimit:
|
||||||
def __init__(self, message_limit: int, interval_limit: int) -> None:
|
def __init__(self, message_limit: int, interval_limit: int) -> None:
|
||||||
self.message_limit = message_limit
|
self.message_limit = message_limit
|
||||||
self.interval_limit = interval_limit
|
self.interval_limit = interval_limit
|
||||||
self.message_list = [] # type: List[float]
|
self.message_list: List[float] = []
|
||||||
self.error_message = "-----> !*!*!*MESSAGE RATE LIMIT REACHED, EXITING*!*!*! <-----\n"
|
self.error_message = "-----> !*!*!*MESSAGE RATE LIMIT REACHED, EXITING*!*!*! <-----\n"
|
||||||
"Is your bot trapped in an infinite loop by reacting to its own messages?"
|
"Is your bot trapped in an infinite loop by reacting to its own messages?"
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ def get_bot_message_handler(bot_name: str) -> Any:
|
||||||
# handler class. Eventually, we want bot's handler classes to
|
# handler class. Eventually, we want bot's handler classes to
|
||||||
# inherit from a common prototype specifying the handle_message
|
# inherit from a common prototype specifying the handle_message
|
||||||
# function.
|
# function.
|
||||||
lib_module = import_module("zulip_bots.bots.{bot}.{bot}".format(bot=bot_name)) # type: Any
|
lib_module: Any = import_module("zulip_bots.bots.{bot}.{bot}".format(bot=bot_name))
|
||||||
return lib_module.handler_class()
|
return lib_module.handler_class()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ class StubBotHandler:
|
||||||
self.reset_transcript()
|
self.reset_transcript()
|
||||||
|
|
||||||
def reset_transcript(self) -> None:
|
def reset_transcript(self) -> None:
|
||||||
self.transcript = [] # type: List[Tuple[str, Dict[str, Any]]]
|
self.transcript: List[Tuple[str, Dict[str, Any]]] = []
|
||||||
|
|
||||||
def identity(self) -> BotIdentity:
|
def identity(self) -> BotIdentity:
|
||||||
return BotIdentity(self.full_name, self.email)
|
return BotIdentity(self.full_name, self.email)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import pkgutil
|
import pkgutil
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
__path__ = pkgutil.extend_path(__path__, __name__) # type: List[str]
|
__path__: List[str] = pkgutil.extend_path(__path__, __name__)
|
||||||
|
|
|
@ -31,7 +31,7 @@ def read_config_section(parser: configparser.ConfigParser, section: str) -> Dict
|
||||||
|
|
||||||
|
|
||||||
def read_config_from_env_vars(bot_name: Optional[str] = None) -> Dict[str, Dict[str, str]]:
|
def read_config_from_env_vars(bot_name: Optional[str] = None) -> Dict[str, Dict[str, str]]:
|
||||||
bots_config = {} # type: Dict[str, Dict[str, str]]
|
bots_config: Dict[str, Dict[str, str]] = {}
|
||||||
json_config = os.environ.get("ZULIP_BOTSERVER_CONFIG")
|
json_config = os.environ.get("ZULIP_BOTSERVER_CONFIG")
|
||||||
|
|
||||||
if json_config is None:
|
if json_config is None:
|
||||||
|
@ -67,7 +67,7 @@ def read_config_file(
|
||||||
) -> Dict[str, Dict[str, str]]:
|
) -> Dict[str, Dict[str, str]]:
|
||||||
parser = parse_config_file(config_file_path)
|
parser = parse_config_file(config_file_path)
|
||||||
|
|
||||||
bots_config = {} # type: Dict[str, Dict[str, str]]
|
bots_config: Dict[str, Dict[str, str]] = {}
|
||||||
if bot_name is None:
|
if bot_name is None:
|
||||||
bots_config = {
|
bots_config = {
|
||||||
section: read_config_section(parser, section) for section in parser.sections()
|
section: read_config_section(parser, section) for section in parser.sections()
|
||||||
|
@ -173,7 +173,7 @@ def init_message_handlers(
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
bots_config = {} # type: Dict[str, Dict[str, str]]
|
bots_config: Dict[str, Dict[str, str]] = {}
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=["POST"])
|
@app.route("/", methods=["POST"])
|
||||||
|
|
Loading…
Add table
Reference in a new issue