Modernize legacy Python 2 syntax with pyupgrade.
Generated by `pyupgrade --py3-plus --keep-percent-format` followed by manual indentation fixes. Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
parent
543eb396b9
commit
e30b3b094b
|
@ -7,7 +7,7 @@ if MYPY:
|
||||||
|
|
||||||
whitespace_rules = [
|
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': '\s+$',
|
{'pattern': r'\s+$',
|
||||||
'strip': '\n',
|
'strip': '\n',
|
||||||
'description': 'Fix trailing whitespace'},
|
'description': 'Fix trailing whitespace'},
|
||||||
{'pattern': '\t',
|
{'pattern': '\t',
|
||||||
|
@ -15,11 +15,11 @@ whitespace_rules = [
|
||||||
'description': 'Fix tab-based whitespace'},
|
'description': 'Fix tab-based whitespace'},
|
||||||
] # type: Rule
|
] # type: Rule
|
||||||
|
|
||||||
markdown_whitespace_rules = list([rule for rule in whitespace_rules if rule['pattern'] != '\s+$']) + [
|
markdown_whitespace_rules = list([rule for rule in whitespace_rules if rule['pattern'] != r'\s+$']) + [
|
||||||
# Two spaces trailing a line with other content is okay--it's a markdown line break.
|
# Two spaces trailing a line with other content is okay--it's a markdown line break.
|
||||||
# This rule finds one space trailing a non-space, three or more trailing spaces, and
|
# This rule finds one space trailing a non-space, three or more trailing spaces, and
|
||||||
# spaces on an empty line.
|
# spaces on an empty line.
|
||||||
{'pattern': '((?<!\s)\s$)|(\s\s\s+$)|(^\s+$)',
|
{'pattern': r'((?<!\s)\s$)|(\s\s\s+$)|(^\s+$)',
|
||||||
'strip': '\n',
|
'strip': '\n',
|
||||||
'description': 'Fix trailing whitespace'},
|
'description': 'Fix trailing whitespace'},
|
||||||
{'pattern': '^#+[A-Za-z0-9]',
|
{'pattern': '^#+[A-Za-z0-9]',
|
||||||
|
@ -30,18 +30,18 @@ markdown_whitespace_rules = list([rule for rule in whitespace_rules if rule['pat
|
||||||
python_rules = RuleList(
|
python_rules = RuleList(
|
||||||
langs=['py'],
|
langs=['py'],
|
||||||
rules=[
|
rules=[
|
||||||
{'pattern': '".*"%\([a-z_].*\)?$',
|
{'pattern': r'".*"%\([a-z_].*\)?$',
|
||||||
'description': 'Missing space around "%"'},
|
'description': 'Missing space around "%"'},
|
||||||
{'pattern': "'.*'%\([a-z_].*\)?$",
|
{'pattern': r"'.*'%\([a-z_].*\)?$",
|
||||||
'description': 'Missing space around "%"'},
|
'description': 'Missing space around "%"'},
|
||||||
# This rule is constructed with + to avoid triggering on itself
|
# This rule is constructed with + to avoid triggering on itself
|
||||||
{'pattern': " =" + '[^ =>~"]',
|
{'pattern': " =" + '[^ =>~"]',
|
||||||
'description': 'Missing whitespace after "="'},
|
'description': 'Missing whitespace after "="'},
|
||||||
{'pattern': '":\w[^"]*$',
|
{'pattern': r'":\w[^"]*$',
|
||||||
'description': 'Missing whitespace after ":"'},
|
'description': 'Missing whitespace after ":"'},
|
||||||
{'pattern': "':\w[^']*$",
|
{'pattern': r"':\w[^']*$",
|
||||||
'description': 'Missing whitespace after ":"'},
|
'description': 'Missing whitespace after ":"'},
|
||||||
{'pattern': "^\s+[#]\w",
|
{'pattern': r"^\s+[#]\w",
|
||||||
'strip': '\n',
|
'strip': '\n',
|
||||||
'description': 'Missing whitespace after "#"'},
|
'description': 'Missing whitespace after "#"'},
|
||||||
{'pattern': "assertEquals[(]",
|
{'pattern': "assertEquals[(]",
|
||||||
|
@ -67,26 +67,26 @@ python_rules = RuleList(
|
||||||
# This next check could have false positives, but it seems pretty
|
# This next check could have false positives, but it seems pretty
|
||||||
# rare; if we find any, they can be added to the exclude list for
|
# rare; if we find any, they can be added to the exclude list for
|
||||||
# this rule.
|
# this rule.
|
||||||
{'pattern': ' % [a-zA-Z0-9_.]*\)?$',
|
{'pattern': r' % [a-zA-Z0-9_.]*\)?$',
|
||||||
'description': 'Used % comprehension without a tuple'},
|
'description': 'Used % comprehension without a tuple'},
|
||||||
{'pattern': '.*%s.* % \([a-zA-Z0-9_.]*\)$',
|
{'pattern': r'.*%s.* % \([a-zA-Z0-9_.]*\)$',
|
||||||
'description': 'Used % comprehension without a tuple'},
|
'description': 'Used % comprehension without a tuple'},
|
||||||
{'pattern': '__future__',
|
{'pattern': '__future__',
|
||||||
'include_only': set(['zulip_bots/zulip_bots/bots/']),
|
'include_only': {'zulip_bots/zulip_bots/bots/'},
|
||||||
'description': 'Bots no longer need __future__ imports.'},
|
'description': 'Bots no longer need __future__ imports.'},
|
||||||
{'pattern': '#!/usr/bin/env python$',
|
{'pattern': '#!/usr/bin/env python$',
|
||||||
'include_only': set(['zulip_bots/']),
|
'include_only': {'zulip_bots/'},
|
||||||
'description': 'Python shebangs must be python3'},
|
'description': 'Python shebangs must be python3'},
|
||||||
{'pattern': '(^|\s)open\s*\(',
|
{'pattern': r'(^|\s)open\s*\(',
|
||||||
'description': 'open() should not be used in Zulip\'s bots. Use functions'
|
'description': 'open() should not be used in Zulip\'s bots. Use functions'
|
||||||
' provided by the bots framework to access the filesystem.',
|
' provided by the bots framework to access the filesystem.',
|
||||||
'include_only': set(['zulip_bots/zulip_bots/bots/'])},
|
'include_only': {'zulip_bots/zulip_bots/bots/'}},
|
||||||
{'pattern': 'pprint',
|
{'pattern': 'pprint',
|
||||||
'description': 'Used pprint, which is most likely a debugging leftover. For user output, use print().'},
|
'description': 'Used pprint, which is most likely a debugging leftover. For user output, use print().'},
|
||||||
{'pattern': '\(BotTestCase\)',
|
{'pattern': r'\(BotTestCase\)',
|
||||||
'bad_lines': ['class TestSomeBot(BotTestCase):'],
|
'bad_lines': ['class TestSomeBot(BotTestCase):'],
|
||||||
'description': 'Bot test cases should directly inherit from BotTestCase *and* DefaultTests.'},
|
'description': 'Bot test cases should directly inherit from BotTestCase *and* DefaultTests.'},
|
||||||
{'pattern': '\(DefaultTests, BotTestCase\)',
|
{'pattern': r'\(DefaultTests, BotTestCase\)',
|
||||||
'bad_lines': ['class TestSomeBot(DefaultTests, BotTestCase):'],
|
'bad_lines': ['class TestSomeBot(DefaultTests, BotTestCase):'],
|
||||||
'good_lines': ['class TestSomeBot(BotTestCase, DefaultTests):'],
|
'good_lines': ['class TestSomeBot(BotTestCase, DefaultTests):'],
|
||||||
'description': 'Bot test cases should inherit from BotTestCase before DefaultTests.'},
|
'description': 'Bot test cases should inherit from BotTestCase before DefaultTests.'},
|
||||||
|
@ -117,9 +117,9 @@ json_rules = RuleList(
|
||||||
)
|
)
|
||||||
|
|
||||||
prose_style_rules = [
|
prose_style_rules = [
|
||||||
{'pattern': '[^\/\#\-\"]([jJ]avascript)', # exclude usage in hrefs/divs
|
{'pattern': '[^\\/\\#\\-\"]([jJ]avascript)', # exclude usage in hrefs/divs
|
||||||
'description': "javascript should be spelled JavaScript"},
|
'description': "javascript should be spelled JavaScript"},
|
||||||
{'pattern': '[^\/\-\.\"\'\_\=\>]([gG]ithub)[^\.\-\_\"\<]', # exclude usage in hrefs/divs
|
{'pattern': '[^\\/\\-\\.\"\'\\_\\=\\>]([gG]ithub)[^\\.\\-\\_\"\\<]', # exclude usage in hrefs/divs
|
||||||
'description': "github should be spelled GitHub"},
|
'description': "github should be spelled GitHub"},
|
||||||
{'pattern': '[oO]rganisation', # exclude usage in hrefs/divs
|
{'pattern': '[oO]rganisation', # exclude usage in hrefs/divs
|
||||||
'description': "Organization is spelled with a z"},
|
'description': "Organization is spelled with a z"},
|
||||||
|
@ -136,7 +136,7 @@ markdown_docs_length_exclude = {
|
||||||
markdown_rules = RuleList(
|
markdown_rules = RuleList(
|
||||||
langs=['md'],
|
langs=['md'],
|
||||||
rules=markdown_whitespace_rules + prose_style_rules + [
|
rules=markdown_whitespace_rules + prose_style_rules + [
|
||||||
{'pattern': '\[(?P<url>[^\]]+)\]\((?P=url)\)',
|
{'pattern': r'\[(?P<url>[^\]]+)\]\((?P=url)\)',
|
||||||
'description': 'Linkified markdown URLs should use cleaner <http://example.com> syntax.'}
|
'description': 'Linkified markdown URLs should use cleaner <http://example.com> syntax.'}
|
||||||
],
|
],
|
||||||
max_length=120,
|
max_length=120,
|
||||||
|
|
|
@ -201,7 +201,7 @@ def print_bots(bots: List[Any], pretty_print: bool) -> None:
|
||||||
print_bots_pretty(bots)
|
print_bots_pretty(bots)
|
||||||
else:
|
else:
|
||||||
for bot in bots:
|
for bot in bots:
|
||||||
print('{0}\t{1}\t{2}\t{3}'.format(bot['name'], bot['status'], bot['email'], bot['site']))
|
print('{}\t{}\t{}\t{}'.format(bot['name'], bot['status'], bot['email'], bot['site']))
|
||||||
|
|
||||||
def print_bots_pretty(bots: List[Any]) -> None:
|
def print_bots_pretty(bots: List[Any]) -> None:
|
||||||
if len(bots) == 0:
|
if len(bots) == 0:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
@ -42,7 +41,7 @@ def create_pipe_event(to_client: zulip.Client, from_bot: Dict[str, Any],
|
||||||
"type": "stream",
|
"type": "stream",
|
||||||
"to": to_bot["stream"],
|
"to": to_bot["stream"],
|
||||||
"subject": subject,
|
"subject": subject,
|
||||||
"content": "**{0}**: {1}".format(msg["sender_full_name"], msg["content"]),
|
"content": "**{}**: {}".format(msg["sender_full_name"], msg["content"]),
|
||||||
"has_attachment": msg.get("has_attachment", False),
|
"has_attachment": msg.get("has_attachment", False),
|
||||||
"has_image": msg.get("has_image", False),
|
"has_image": msg.get("has_image", False),
|
||||||
"has_link": msg.get("has_link", False)
|
"has_link": msg.get("has_link", False)
|
||||||
|
|
|
@ -116,7 +116,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
|
||||||
"to": self.stream,
|
"to": self.stream,
|
||||||
"subject": self.topic,
|
"subject": self.topic,
|
||||||
"content": content,
|
"content": content,
|
||||||
"content": "**{0}**: {1}".format(sender, content),
|
"content": "**{}**: {}".format(sender, content),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
def on_dccmsg(self, c, e):
|
def on_dccmsg(self, c, e):
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Change these values to configure authentication for your codebase account
|
# Change these values to configure authentication for your codebase account
|
||||||
# Note that this is the Codebase API Username, found in the Settings page
|
# Note that this is the Codebase API Username, found in the Settings page
|
||||||
# for your account
|
# for your account
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Zulip mirror of Codebase HQ activity
|
# Zulip mirror of Codebase HQ activity
|
||||||
# The "zulip_codebase_mirror" script is run continuously, possibly on a work
|
# The "zulip_codebase_mirror" script is run continuously, possibly on a work
|
||||||
|
@ -256,7 +255,7 @@ def run_mirror():
|
||||||
since = default_since()
|
since = default_since()
|
||||||
else:
|
else:
|
||||||
since = datetime.fromtimestamp(float(timestamp), tz=pytz.utc)
|
since = datetime.fromtimestamp(float(timestamp), tz=pytz.utc)
|
||||||
except (ValueError, IOError) as e:
|
except (ValueError, OSError) as e:
|
||||||
logging.warn("Could not open resume file: %s" % (str(e)))
|
logging.warn("Could not open resume file: %s" % (str(e)))
|
||||||
since = default_since()
|
since = default_since()
|
||||||
|
|
||||||
|
@ -289,13 +288,13 @@ def check_permissions():
|
||||||
if config.LOG_FILE:
|
if config.LOG_FILE:
|
||||||
try:
|
try:
|
||||||
open(config.LOG_FILE, "w")
|
open(config.LOG_FILE, "w")
|
||||||
except IOError as e:
|
except OSError as e:
|
||||||
sys.stderr.write("Could not open up log for writing:")
|
sys.stderr.write("Could not open up log for writing:")
|
||||||
sys.stderr.write(str(e))
|
sys.stderr.write(str(e))
|
||||||
# check that the resume file can be written (this creates if it doesn't exist)
|
# check that the resume file can be written (this creates if it doesn't exist)
|
||||||
try:
|
try:
|
||||||
open(config.RESUME_FILE, "a+")
|
open(config.RESUME_FILE, "a+")
|
||||||
except IOError as e:
|
except OSError as e:
|
||||||
sys.stderr.write("Could not open up the file %s for reading and writing" % (config.RESUME_FILE,))
|
sys.stderr.write("Could not open up the file %s for reading and writing" % (config.RESUME_FILE,))
|
||||||
sys.stderr.write(str(e))
|
sys.stderr.write(str(e))
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Zulip notification post-receive hook.
|
# Zulip notification post-receive hook.
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
from typing import Dict, Text, Optional
|
from typing import Dict, Text, Optional
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ def commit_notice_destination(repo, branch, commit):
|
||||||
# type: (Text, Text, Text) -> Optional[Dict[Text, Text]]
|
# type: (Text, Text, Text) -> Optional[Dict[Text, Text]]
|
||||||
if branch in ["master", "test-post-receive"]:
|
if branch in ["master", "test-post-receive"]:
|
||||||
return dict(stream = STREAM_NAME,
|
return dict(stream = STREAM_NAME,
|
||||||
subject = u"%s" % (branch,))
|
subject = "%s" % (branch,))
|
||||||
|
|
||||||
# Return None for cases where you don't want a notice sent
|
# Return None for cases where you don't want a notice sent
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -100,7 +100,7 @@ def get_credentials():
|
||||||
return credentials
|
return credentials
|
||||||
except client.Error:
|
except client.Error:
|
||||||
logging.exception('Error while trying to open the `google-credentials.json` file.')
|
logging.exception('Error while trying to open the `google-credentials.json` file.')
|
||||||
except IOError:
|
except OSError:
|
||||||
logging.error("Run the get-google-credentials script from this directory first.")
|
logging.error("Run the get-google-credentials script from this directory first.")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Zulip hook for Mercurial changeset pushes.
|
# Zulip hook for Mercurial changeset pushes.
|
||||||
#
|
#
|
||||||
|
@ -35,7 +34,7 @@ def format_summary_line(web_url, user, base, tip, branch, node):
|
||||||
formatted_commit_count = "{revcount} commit{s}".format(
|
formatted_commit_count = "{revcount} commit{s}".format(
|
||||||
revcount=revcount, s=plural)
|
revcount=revcount, s=plural)
|
||||||
|
|
||||||
return u"**{user}** pushed {commits} to **{branch}** (`{tip}:{node}`):\n\n".format(
|
return "**{user}** pushed {commits} to **{branch}** (`{tip}:{node}`):\n\n".format(
|
||||||
user=user, commits=formatted_commit_count, branch=branch, tip=tip,
|
user=user, commits=formatted_commit_count, branch=branch, tip=tip,
|
||||||
node=node[:12])
|
node=node[:12])
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ class JabberToZulipBot(ClientXMPP):
|
||||||
|
|
||||||
def private(self, msg):
|
def private(self, msg):
|
||||||
# type: (JabberMessage) -> None
|
# type: (JabberMessage) -> None
|
||||||
if options.mode == 'public' or msg['thread'] == u'\u1FFFE':
|
if options.mode == 'public' or msg['thread'] == '\u1FFFE':
|
||||||
return
|
return
|
||||||
sender = jid_to_zulip(msg["from"])
|
sender = jid_to_zulip(msg["from"])
|
||||||
recipient = jid_to_zulip(msg["to"])
|
recipient = jid_to_zulip(msg["to"])
|
||||||
|
@ -178,7 +178,7 @@ class JabberToZulipBot(ClientXMPP):
|
||||||
|
|
||||||
def group(self, msg):
|
def group(self, msg):
|
||||||
# type: (JabberMessage) -> None
|
# type: (JabberMessage) -> None
|
||||||
if options.mode == 'personal' or msg["thread"] == u'\u1FFFE':
|
if options.mode == 'personal' or msg["thread"] == '\u1FFFE':
|
||||||
return
|
return
|
||||||
|
|
||||||
subject = msg["subject"]
|
subject = msg["subject"]
|
||||||
|
@ -212,7 +212,7 @@ class JabberToZulipBot(ClientXMPP):
|
||||||
else:
|
else:
|
||||||
return jid
|
return jid
|
||||||
|
|
||||||
class ZulipToJabberBot(object):
|
class ZulipToJabberBot:
|
||||||
def __init__(self, zulip_client):
|
def __init__(self, zulip_client):
|
||||||
# type: (Client) -> None
|
# type: (Client) -> None
|
||||||
self.client = zulip_client
|
self.client = zulip_client
|
||||||
|
@ -254,7 +254,7 @@ class ZulipToJabberBot(object):
|
||||||
mto = jabber_recipient,
|
mto = jabber_recipient,
|
||||||
mbody = msg['content'],
|
mbody = msg['content'],
|
||||||
mtype = 'groupchat')
|
mtype = 'groupchat')
|
||||||
outgoing['thread'] = u'\u1FFFE'
|
outgoing['thread'] = '\u1FFFE'
|
||||||
outgoing.send()
|
outgoing.send()
|
||||||
|
|
||||||
def private_message(self, msg):
|
def private_message(self, msg):
|
||||||
|
@ -271,7 +271,7 @@ class ZulipToJabberBot(object):
|
||||||
mto = jabber_recipient,
|
mto = jabber_recipient,
|
||||||
mbody = msg['content'],
|
mbody = msg['content'],
|
||||||
mtype = 'chat')
|
mtype = 'chat')
|
||||||
outgoing['thread'] = u'\u1FFFE'
|
outgoing['thread'] = '\u1FFFE'
|
||||||
outgoing.send()
|
outgoing.send()
|
||||||
|
|
||||||
def process_subscription(self, event):
|
def process_subscription(self, event):
|
||||||
|
@ -415,9 +415,9 @@ option does not affect login credentials.'''.replace("\n", " "))
|
||||||
|
|
||||||
config = SafeConfigParser()
|
config = SafeConfigParser()
|
||||||
try:
|
try:
|
||||||
with open(config_file, 'r') as f:
|
with open(config_file) as f:
|
||||||
config.readfp(f, config_file)
|
config.readfp(f, config_file)
|
||||||
except IOError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
for option in ("jid", "jabber_password", "conference_domain", "mode", "zulip_email_suffix",
|
for option in ("jid", "jabber_password", "conference_domain", "mode", "zulip_email_suffix",
|
||||||
"jabber_server_address", "jabber_server_port"):
|
"jabber_server_address", "jabber_server_port"):
|
||||||
|
|
|
@ -112,8 +112,8 @@ if __name__ == "__main__":
|
||||||
open(lock_path, "w").write("1")
|
open(lock_path, "w").write("1")
|
||||||
zulip_client = zulip.init_from_options(args)
|
zulip_client = zulip.init_from_options(args)
|
||||||
try:
|
try:
|
||||||
log_files = json.loads(open(args.control_path, "r").read())
|
log_files = json.loads(open(args.control_path).read())
|
||||||
except (json.JSONDecodeError, IOError): # type: ignore # error: Cannot determine type of 'IOError'
|
except (json.JSONDecodeError, OSError): # type: ignore # error: Cannot determine type of 'IOError'
|
||||||
print("Could not load control data from %s" % (args.control_path,))
|
print("Could not load control data from %s" % (args.control_path,))
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Zulip notification post-receive hook.
|
# Zulip notification post-receive hook.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# https://github.com/python/mypy/issues/1141
|
# https://github.com/python/mypy/issues/1141
|
||||||
from typing import Dict, Text, Optional
|
from typing import Dict, Text, Optional
|
||||||
|
|
||||||
|
@ -25,7 +23,7 @@ def deployment_notice_destination(branch):
|
||||||
# type: (str) -> Optional[Dict[str, Text]]
|
# type: (str) -> Optional[Dict[str, Text]]
|
||||||
if branch in ['master', 'test-post-receive']:
|
if branch in ['master', 'test-post-receive']:
|
||||||
return dict(stream = 'deployments',
|
return dict(stream = 'deployments',
|
||||||
subject = u'%s' % (branch,))
|
subject = '%s' % (branch,))
|
||||||
|
|
||||||
# Return None for cases where you don't want a notice sent
|
# Return None for cases where you don't want a notice sent
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -339,7 +339,7 @@ def setP4ExecBit(file, mode):
|
||||||
if not isModeExec(mode):
|
if not isModeExec(mode):
|
||||||
p4Type = getP4OpenedType(file)
|
p4Type = getP4OpenedType(file)
|
||||||
p4Type = re.sub('^([cku]?)x(.*)', '\\1\\2', p4Type)
|
p4Type = re.sub('^([cku]?)x(.*)', '\\1\\2', p4Type)
|
||||||
p4Type = re.sub('(.*?\+.*?)x(.*?)', '\\1\\2', p4Type)
|
p4Type = re.sub(r'(.*?\+.*?)x(.*?)', '\\1\\2', p4Type)
|
||||||
if p4Type[-1] == "+":
|
if p4Type[-1] == "+":
|
||||||
p4Type = p4Type[0:-1]
|
p4Type = p4Type[0:-1]
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ def getP4OpenedType(file):
|
||||||
# Returns the perforce file type for the given file.
|
# Returns the perforce file type for the given file.
|
||||||
|
|
||||||
result = p4_read_pipe(["opened", wildcard_encode(file)])
|
result = p4_read_pipe(["opened", wildcard_encode(file)])
|
||||||
match = re.match(".*\((.+)\)\r?$", result)
|
match = re.match(".*\\((.+)\\)\r?$", result)
|
||||||
if match:
|
if match:
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
else:
|
else:
|
||||||
|
@ -378,7 +378,7 @@ def getGitTags():
|
||||||
def diffTreePattern():
|
def diffTreePattern():
|
||||||
# This is a simple generator for the diff tree regex pattern. This could be
|
# This is a simple generator for the diff tree regex pattern. This could be
|
||||||
# a class variable if this and parseDiffTreeEntry were a part of a class.
|
# a class variable if this and parseDiffTreeEntry were a part of a class.
|
||||||
pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
|
pattern = re.compile(':(\\d+) (\\d+) (\\w+) (\\w+) ([A-Z])(\\d+)?\t(.*?)((\t(.*))|$)')
|
||||||
while True:
|
while True:
|
||||||
yield pattern
|
yield pattern
|
||||||
|
|
||||||
|
@ -820,13 +820,13 @@ def wildcard_present(path):
|
||||||
m = re.search("[*#@%]", path)
|
m = re.search("[*#@%]", path)
|
||||||
return m is not None
|
return m is not None
|
||||||
|
|
||||||
class Command(object):
|
class Command:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.usage = "usage: %prog [options]"
|
self.usage = "usage: %prog [options]"
|
||||||
self.needsGit = True
|
self.needsGit = True
|
||||||
self.verbose = False
|
self.verbose = False
|
||||||
|
|
||||||
class P4UserMap(object):
|
class P4UserMap:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.userMapFromPerforceServer = False
|
self.userMapFromPerforceServer = False
|
||||||
self.myP4UserId = None
|
self.myP4UserId = None
|
||||||
|
@ -883,7 +883,7 @@ class P4UserMap(object):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
entry = line.strip().split("\t")
|
entry = line.strip().split("\t")
|
||||||
self.users[entry[0]] = entry[1]
|
self.users[entry[0]] = entry[1]
|
||||||
except IOError:
|
except OSError:
|
||||||
self.getUserMapFromPerforceServer()
|
self.getUserMapFromPerforceServer()
|
||||||
|
|
||||||
class P4Debug(Command):
|
class P4Debug(Command):
|
||||||
|
@ -1056,7 +1056,7 @@ class P4Submit(Command, P4UserMap):
|
||||||
(handle, outFileName) = tempfile.mkstemp(dir='.')
|
(handle, outFileName) = tempfile.mkstemp(dir='.')
|
||||||
try:
|
try:
|
||||||
outFile = os.fdopen(handle, "w+")
|
outFile = os.fdopen(handle, "w+")
|
||||||
inFile = open(file, "r")
|
inFile = open(file)
|
||||||
regexp = re.compile(pattern, re.VERBOSE)
|
regexp = re.compile(pattern, re.VERBOSE)
|
||||||
for line in inFile.readlines():
|
for line in inFile.readlines():
|
||||||
line = regexp.sub(r'$\1$', line)
|
line = regexp.sub(r'$\1$', line)
|
||||||
|
@ -1391,7 +1391,7 @@ class P4Submit(Command, P4UserMap):
|
||||||
newdiff += "==== new file ====\n"
|
newdiff += "==== new file ====\n"
|
||||||
newdiff += "--- /dev/null\n"
|
newdiff += "--- /dev/null\n"
|
||||||
newdiff += "+++ %s\n" % newFile
|
newdiff += "+++ %s\n" % newFile
|
||||||
f = open(newFile, "r")
|
f = open(newFile)
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
newdiff += "+" + line
|
newdiff += "+" + line
|
||||||
f.close()
|
f.close()
|
||||||
|
@ -1773,7 +1773,7 @@ class P4Submit(Command, P4UserMap):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class View(object):
|
class View:
|
||||||
"""Represent a p4 view ("p4 help views"), and map files in a
|
"""Represent a p4 view ("p4 help views"), and map files in a
|
||||||
repo according to the view."""
|
repo according to the view."""
|
||||||
|
|
||||||
|
@ -2377,7 +2377,7 @@ class P4Sync(Command, P4UserMap):
|
||||||
# find the corresponding git commit; take the oldest commit
|
# find the corresponding git commit; take the oldest commit
|
||||||
changelist = int(change['change'])
|
changelist = int(change['change'])
|
||||||
gitCommit = read_pipe(["git", "rev-list", "--max-count=1",
|
gitCommit = read_pipe(["git", "rev-list", "--max-count=1",
|
||||||
"--reverse", ":/\[git-p4:.*change = %d\]" % changelist])
|
"--reverse", r":/\[git-p4:.*change = %d\]" % changelist])
|
||||||
if len(gitCommit) == 0:
|
if len(gitCommit) == 0:
|
||||||
print("could not find git commit for changelist %d" % changelist)
|
print("could not find git commit for changelist %d" % changelist)
|
||||||
else:
|
else:
|
||||||
|
@ -2657,7 +2657,7 @@ class P4Sync(Command, P4UserMap):
|
||||||
self.initialParent)
|
self.initialParent)
|
||||||
# only needed once, to connect to the previous commit
|
# only needed once, to connect to the previous commit
|
||||||
self.initialParent = ""
|
self.initialParent = ""
|
||||||
except IOError:
|
except OSError:
|
||||||
print(self.gitError.read())
|
print(self.gitError.read())
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
@ -2712,7 +2712,7 @@ class P4Sync(Command, P4UserMap):
|
||||||
self.updateOptionDict(details)
|
self.updateOptionDict(details)
|
||||||
try:
|
try:
|
||||||
self.commit(details, self.extractFilesFromCommit(details), self.branch)
|
self.commit(details, self.extractFilesFromCommit(details), self.branch)
|
||||||
except IOError:
|
except OSError:
|
||||||
print("IO error with git fast-import. Is your git version recent enough?")
|
print("IO error with git fast-import. Is your git version recent enough?")
|
||||||
print(self.gitError.read())
|
print(self.gitError.read())
|
||||||
|
|
||||||
|
@ -2878,7 +2878,7 @@ class P4Sync(Command, P4UserMap):
|
||||||
if len(self.changesFile) == 0:
|
if len(self.changesFile) == 0:
|
||||||
revision = "#head"
|
revision = "#head"
|
||||||
|
|
||||||
p = re.sub ("\.\.\.$", "", p)
|
p = re.sub (r"\.\.\.$", "", p)
|
||||||
if not p.endswith("/"):
|
if not p.endswith("/"):
|
||||||
p += "/"
|
p += "/"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
'''Zulip notification change-commit hook.
|
'''Zulip notification change-commit hook.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from typing import Dict, Optional, Text
|
from typing import Dict, Optional, Text
|
||||||
|
|
||||||
# Change these values to configure authentication for the plugin
|
# Change these values to configure authentication for the plugin
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# RSS integration for Zulip
|
# RSS integration for Zulip
|
||||||
#
|
#
|
||||||
|
@ -174,9 +173,9 @@ def send_zulip(entry, feed_name):
|
||||||
return client.send_message(message)
|
return client.send_message(message)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(opts.feed_file, "r") as f:
|
with open(opts.feed_file) as f:
|
||||||
feed_urls = [feed.strip() for feed in f.readlines()] # type: List[str]
|
feed_urls = [feed.strip() for feed in f.readlines()] # type: List[str]
|
||||||
except IOError:
|
except OSError:
|
||||||
log_error_and_exit("Unable to read feed file at %s." % (opts.feed_file,))
|
log_error_and_exit("Unable to read feed file at %s." % (opts.feed_file,))
|
||||||
|
|
||||||
client = zulip.Client(email=opts.zulip_email, api_key=opts.zulip_api_key,
|
client = zulip.Client(email=opts.zulip_email, api_key=opts.zulip_api_key,
|
||||||
|
@ -189,9 +188,9 @@ 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, "r") as f:
|
with open(feed_file) as f:
|
||||||
old_feed_hashes = dict((line.strip(), True) for line in f.readlines()) # type: Dict[str, bool]
|
old_feed_hashes = {line.strip(): True for line in f.readlines()} # type: Dict[str, bool]
|
||||||
except IOError:
|
except OSError:
|
||||||
old_feed_hashes = {}
|
old_feed_hashes = {}
|
||||||
|
|
||||||
new_hashes = [] # type: List[str]
|
new_hashes = [] # type: List[str]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Zulip notification post-commit hook.
|
# Zulip notification post-commit hook.
|
||||||
#
|
#
|
||||||
|
@ -39,7 +38,7 @@ path, rev = sys.argv[1:] # type: Tuple[Text, Text]
|
||||||
path = "file://" + path
|
path = "file://" + path
|
||||||
|
|
||||||
entry = svn.log(path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev))[0] # type: Dict[Text, Any]
|
entry = svn.log(path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev))[0] # type: Dict[Text, Any]
|
||||||
message = "**{0}** committed revision r{1} to `{2}`.\n\n> {3}".format(
|
message = "**{}** committed revision r{} to `{}`.\n\n> {}".format(
|
||||||
entry['author'],
|
entry['author'],
|
||||||
rev,
|
rev,
|
||||||
path.split('/')[-1],
|
path.split('/')[-1],
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from typing import Dict, Optional, Text
|
from typing import Dict, Optional, Text
|
||||||
|
|
||||||
# Change these values to configure authentication for the plugin
|
# Change these values to configure authentication for the plugin
|
||||||
|
@ -25,7 +23,7 @@ def commit_notice_destination(path, commit):
|
||||||
repo = path.split('/')[-1]
|
repo = path.split('/')[-1]
|
||||||
if repo not in ["evil-master-plan", "my-super-secret-repository"]:
|
if repo not in ["evil-master-plan", "my-super-secret-repository"]:
|
||||||
return dict(stream = "commits",
|
return dict(stream = "commits",
|
||||||
subject = u"%s" % (repo,))
|
subject = "%s" % (repo,))
|
||||||
|
|
||||||
# Return None for cases where you don't want a notice sent
|
# Return None for cases where you don't want a notice sent
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Zulip trac plugin -- sends zulips when tickets change.
|
# Zulip trac plugin -- sends zulips when tickets change.
|
||||||
#
|
#
|
||||||
# Install by copying this file and zulip_trac_config.py to the trac
|
# Install by copying this file and zulip_trac_config.py to the trac
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# See zulip_trac.py for installation and configuration instructions
|
# See zulip_trac.py for installation and configuration instructions
|
||||||
|
|
||||||
# Change these constants to configure the plugin:
|
# Change these constants to configure the plugin:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# An easy Trello integration for Zulip.
|
# An easy Trello integration for Zulip.
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ def get_model_id(options):
|
||||||
params=params
|
params=params
|
||||||
)
|
)
|
||||||
|
|
||||||
if trello_response.status_code is not 200:
|
if trello_response.status_code != 200:
|
||||||
print('Error: Can\'t get the idModel. Please check the configuration')
|
print('Error: Can\'t get the idModel. Please check the configuration')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ def get_webhook_id(options, id_model):
|
||||||
data=data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
if trello_response.status_code is not 200:
|
if trello_response.status_code != 200:
|
||||||
print('Error: Can\'t create the Webhook:', trello_response.text)
|
print('Error: Can\'t create the Webhook:', trello_response.text)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Twitter integration for Zulip
|
# Twitter integration for Zulip
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ for tries in range(10):
|
||||||
if missing == 0:
|
if missing == 0:
|
||||||
actually_subscribed = True
|
actually_subscribed = True
|
||||||
break
|
break
|
||||||
except IOError as e:
|
except OSError as e:
|
||||||
if "SERVNAK received" in e: # type: ignore # https://github.com/python/mypy/issues/2118
|
if "SERVNAK received" in e: # type: ignore # https://github.com/python/mypy/issues/2118
|
||||||
logger.error("SERVNAK repeatedly received, punting rest of test")
|
logger.error("SERVNAK repeatedly received, punting rest of test")
|
||||||
else:
|
else:
|
||||||
|
@ -283,8 +283,8 @@ def process_keys(content_list):
|
||||||
key_counts[key] = 0
|
key_counts[key] = 0
|
||||||
for key in content_keys:
|
for key in content_keys:
|
||||||
key_counts[key] += 1
|
key_counts[key] += 1
|
||||||
z_missing = set(key for key in zhkeys.keys() if key_counts[key] == 0)
|
z_missing = {key for key in zhkeys.keys() if key_counts[key] == 0}
|
||||||
h_missing = set(key for key in hzkeys.keys() if key_counts[key] == 0)
|
h_missing = {key for key in hzkeys.keys() if key_counts[key] == 0}
|
||||||
duplicates = any(val > 1 for val in key_counts.values())
|
duplicates = any(val > 1 for val in key_counts.values())
|
||||||
success = all(val == 1 for val in key_counts.values())
|
success = all(val == 1 for val in key_counts.values())
|
||||||
return key_counts, z_missing, h_missing, duplicates, success
|
return key_counts, z_missing, h_missing, duplicates, success
|
||||||
|
|
|
@ -26,7 +26,7 @@ session_path = "/home/zulip/zephyr_sessions/%s" % (program_name,)
|
||||||
# Preserve mail zephyrs forwarding setting across rewriting the config file
|
# Preserve mail zephyrs forwarding setting across rewriting the config file
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if "--forward-mail-zephyrs" in open(supervisor_path, "r").read():
|
if "--forward-mail-zephyrs" in open(supervisor_path).read():
|
||||||
template_data = template_data.replace("--use-sessions", "--use-sessions --forward-mail-zephyrs")
|
template_data = template_data.replace("--use-sessions", "--use-sessions --forward-mail-zephyrs")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -20,7 +20,7 @@ import select
|
||||||
|
|
||||||
DEFAULT_SITE = "https://api.zulip.com"
|
DEFAULT_SITE = "https://api.zulip.com"
|
||||||
|
|
||||||
class States(object):
|
class States:
|
||||||
Startup, ZulipToZephyr, ZephyrToZulip, ChildSending = list(range(4))
|
Startup, ZulipToZephyr, ZephyrToZulip, ChildSending = list(range(4))
|
||||||
CURRENT_STATE = States.Startup
|
CURRENT_STATE = States.Startup
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ def zephyr_bulk_subscribe(subs):
|
||||||
# type: (List[Tuple[str, str, str]]) -> None
|
# type: (List[Tuple[str, str, str]]) -> None
|
||||||
try:
|
try:
|
||||||
zephyr._z.subAll(subs)
|
zephyr._z.subAll(subs)
|
||||||
except IOError:
|
except OSError:
|
||||||
# Since we haven't added the subscription to
|
# Since we haven't added the subscription to
|
||||||
# current_zephyr_subs yet, we can just return (so that we'll
|
# current_zephyr_subs yet, we can just return (so that we'll
|
||||||
# continue processing normal messages) and we'll end up
|
# continue processing normal messages) and we'll end up
|
||||||
|
@ -153,7 +153,7 @@ def zephyr_bulk_subscribe(subs):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
actual_zephyr_subs = [cls for (cls, _, _) in zephyr._z.getSubscriptions()]
|
actual_zephyr_subs = [cls for (cls, _, _) in zephyr._z.getSubscriptions()]
|
||||||
except IOError:
|
except OSError:
|
||||||
logger.exception("Error getting current Zephyr subscriptions")
|
logger.exception("Error getting current Zephyr subscriptions")
|
||||||
# Don't add anything to current_zephyr_subs so that we'll
|
# Don't add anything to current_zephyr_subs so that we'll
|
||||||
# retry the next time we check for streams to subscribe to
|
# retry the next time we check for streams to subscribe to
|
||||||
|
@ -169,7 +169,7 @@ def zephyr_bulk_subscribe(subs):
|
||||||
# missing 15 seconds of messages on the affected
|
# missing 15 seconds of messages on the affected
|
||||||
# classes
|
# classes
|
||||||
zephyr._z.sub(cls, instance, recipient)
|
zephyr._z.sub(cls, instance, recipient)
|
||||||
except IOError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
current_zephyr_subs.add(cls)
|
current_zephyr_subs.add(cls)
|
||||||
|
@ -177,7 +177,7 @@ def zephyr_bulk_subscribe(subs):
|
||||||
def update_subscriptions():
|
def update_subscriptions():
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
try:
|
try:
|
||||||
f = open(options.stream_file_path, "r")
|
f = open(options.stream_file_path)
|
||||||
public_streams = json.loads(f.read())
|
public_streams = json.loads(f.read())
|
||||||
f.close()
|
f.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -217,7 +217,7 @@ def maybe_restart_mirroring_script():
|
||||||
maybe_kill_child()
|
maybe_kill_child()
|
||||||
try:
|
try:
|
||||||
zephyr._z.cancelSubs()
|
zephyr._z.cancelSubs()
|
||||||
except IOError:
|
except OSError:
|
||||||
# We don't care whether we failed to cancel subs properly, but we should log it
|
# We don't care whether we failed to cancel subs properly, but we should log it
|
||||||
logger.exception("")
|
logger.exception("")
|
||||||
while True:
|
while True:
|
||||||
|
@ -288,14 +288,14 @@ def parse_crypt_table(zephyr_class, instance):
|
||||||
# type: (Text, str) -> Optional[str]
|
# type: (Text, str) -> Optional[str]
|
||||||
try:
|
try:
|
||||||
crypt_table = open(os.path.join(os.environ["HOME"], ".crypt-table"))
|
crypt_table = open(os.path.join(os.environ["HOME"], ".crypt-table"))
|
||||||
except IOError:
|
except OSError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for line in crypt_table.readlines():
|
for line in crypt_table.readlines():
|
||||||
if line.strip() == "":
|
if line.strip() == "":
|
||||||
# Ignore blank lines
|
# Ignore blank lines
|
||||||
continue
|
continue
|
||||||
match = re.match("^crypt-(?P<class>\S+):\s+((?P<algorithm>(AES|DES)):\s+)?(?P<keypath>\S+)$", line)
|
match = re.match(r"^crypt-(?P<class>\S+):\s+((?P<algorithm>(AES|DES)):\s+)?(?P<keypath>\S+)$", line)
|
||||||
if match is None:
|
if match is None:
|
||||||
# Malformed crypt_table line
|
# Malformed crypt_table line
|
||||||
logger.debug("Invalid crypt_table line!")
|
logger.debug("Invalid crypt_table line!")
|
||||||
|
@ -464,7 +464,7 @@ def zephyr_init_autoretry():
|
||||||
zephyr.init()
|
zephyr.init()
|
||||||
backoff.succeed()
|
backoff.succeed()
|
||||||
return
|
return
|
||||||
except IOError:
|
except OSError:
|
||||||
logger.exception("Error initializing Zephyr library (retrying). Traceback:")
|
logger.exception("Error initializing Zephyr library (retrying). Traceback:")
|
||||||
backoff.fail()
|
backoff.fail()
|
||||||
|
|
||||||
|
@ -475,12 +475,12 @@ def zephyr_load_session_autoretry(session_path):
|
||||||
backoff = zulip.RandomExponentialBackoff()
|
backoff = zulip.RandomExponentialBackoff()
|
||||||
while backoff.keep_going():
|
while backoff.keep_going():
|
||||||
try:
|
try:
|
||||||
session = open(session_path, "r").read()
|
session = open(session_path).read()
|
||||||
zephyr._z.initialize()
|
zephyr._z.initialize()
|
||||||
zephyr._z.load_session(session)
|
zephyr._z.load_session(session)
|
||||||
zephyr.__inited = True
|
zephyr.__inited = True
|
||||||
return
|
return
|
||||||
except IOError:
|
except OSError:
|
||||||
logger.exception("Error loading saved Zephyr session (retrying). Traceback:")
|
logger.exception("Error loading saved Zephyr session (retrying). Traceback:")
|
||||||
backoff.fail()
|
backoff.fail()
|
||||||
|
|
||||||
|
@ -494,7 +494,7 @@ def zephyr_subscribe_autoretry(sub):
|
||||||
zephyr.Subscriptions().add(sub)
|
zephyr.Subscriptions().add(sub)
|
||||||
backoff.succeed()
|
backoff.succeed()
|
||||||
return
|
return
|
||||||
except IOError:
|
except OSError:
|
||||||
# Probably a SERVNAK from the zephyr server, but log the
|
# Probably a SERVNAK from the zephyr server, but log the
|
||||||
# traceback just in case it's something else
|
# traceback just in case it's something else
|
||||||
logger.exception("Error subscribing to personals (retrying). Traceback:")
|
logger.exception("Error subscribing to personals (retrying). Traceback:")
|
||||||
|
@ -522,7 +522,7 @@ def zephyr_to_zulip(options):
|
||||||
open(options.session_path, "w").write(zephyr._z.dump_session())
|
open(options.session_path, "w").write(zephyr._z.dump_session())
|
||||||
|
|
||||||
if options.logs_to_resend is not None:
|
if options.logs_to_resend is not None:
|
||||||
with open(options.logs_to_resend, 'r') as log:
|
with open(options.logs_to_resend) as log:
|
||||||
for ln in log:
|
for ln in log:
|
||||||
try:
|
try:
|
||||||
zeph = json.loads(ln)
|
zeph = json.loads(ln)
|
||||||
|
@ -884,7 +884,7 @@ def parse_zephyr_subs(verbose=False):
|
||||||
logger.error("Couldn't find ~/.zephyr.subs!")
|
logger.error("Couldn't find ~/.zephyr.subs!")
|
||||||
return zephyr_subscriptions
|
return zephyr_subscriptions
|
||||||
|
|
||||||
for line in open(subs_file, "r").readlines():
|
for line in open(subs_file).readlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if len(line) == 0:
|
if len(line) == 0:
|
||||||
continue
|
continue
|
||||||
|
@ -1039,7 +1039,7 @@ def die_gracefully(signal, frame):
|
||||||
try:
|
try:
|
||||||
# zephyr=>zulip processes may have added subs, so run cancelSubs
|
# zephyr=>zulip processes may have added subs, so run cancelSubs
|
||||||
zephyr._z.cancelSubs()
|
zephyr._z.cancelSubs()
|
||||||
except IOError:
|
except OSError:
|
||||||
# We don't care whether we failed to cancel subs properly, but we should log it
|
# We don't care whether we failed to cancel subs properly, but we should log it
|
||||||
logger.exception("")
|
logger.exception("")
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Any, Dict, Generator, List, Tuple
|
from typing import Any, Dict, Generator, List, Tuple
|
||||||
|
@ -9,7 +8,7 @@ import sys
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
with open("README.md", "r") as fh:
|
with open("README.md") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
def version():
|
def version():
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
import time
|
import time
|
||||||
|
@ -34,7 +32,7 @@ requests_json_is_function = callable(requests.Response.json)
|
||||||
|
|
||||||
API_VERSTRING = "v1/"
|
API_VERSTRING = "v1/"
|
||||||
|
|
||||||
class CountingBackoff(object):
|
class CountingBackoff:
|
||||||
def __init__(self, maximum_retries=10, timeout_success_equivalent=None, delay_cap=90.0):
|
def __init__(self, maximum_retries=10, timeout_success_equivalent=None, delay_cap=90.0):
|
||||||
# type: (int, Optional[float], float) -> None
|
# type: (int, Optional[float], float) -> None
|
||||||
self.number_of_retries = 0
|
self.number_of_retries = 0
|
||||||
|
@ -70,7 +68,7 @@ class CountingBackoff(object):
|
||||||
class RandomExponentialBackoff(CountingBackoff):
|
class RandomExponentialBackoff(CountingBackoff):
|
||||||
def fail(self):
|
def fail(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
super(RandomExponentialBackoff, self).fail()
|
super().fail()
|
||||||
# Exponential growth with ratio sqrt(2); compute random delay
|
# Exponential growth with ratio sqrt(2); compute random delay
|
||||||
# between x and 2x where x is growing exponentially
|
# between x and 2x where x is growing exponentially
|
||||||
delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
|
delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
|
||||||
|
@ -278,7 +276,7 @@ class MissingURLError(ZulipError):
|
||||||
class UnrecoverableNetworkError(ZulipError):
|
class UnrecoverableNetworkError(ZulipError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Client(object):
|
class Client:
|
||||||
def __init__(self, email=None, api_key=None, config_file=None,
|
def __init__(self, email=None, api_key=None, config_file=None,
|
||||||
verbose=False, retry_on_errors=True,
|
verbose=False, retry_on_errors=True,
|
||||||
site=None, client=None,
|
site=None, client=None,
|
||||||
|
@ -324,7 +322,7 @@ class Client(object):
|
||||||
|
|
||||||
if config_file is not None and os.path.exists(config_file):
|
if config_file is not None and os.path.exists(config_file):
|
||||||
config = SafeConfigParser()
|
config = SafeConfigParser()
|
||||||
with open(config_file, 'r') as f:
|
with open(config_file) as f:
|
||||||
config.readfp(f, config_file)
|
config.readfp(f, config_file)
|
||||||
if api_key is None:
|
if api_key is None:
|
||||||
api_key = config.get("api", "key")
|
api_key = config.get("api", "key")
|
||||||
|
@ -438,7 +436,7 @@ class Client(object):
|
||||||
try:
|
try:
|
||||||
vendor = platform.system()
|
vendor = platform.system()
|
||||||
vendor_version = platform.release()
|
vendor_version = platform.release()
|
||||||
except IOError:
|
except OSError:
|
||||||
# If the calling process is handling SIGCHLD, platform.system() can
|
# If the calling process is handling SIGCHLD, platform.system() can
|
||||||
# fail with an IOError. See http://bugs.python.org/issue9127
|
# fail with an IOError. See http://bugs.python.org/issue9127
|
||||||
pass
|
pass
|
||||||
|
@ -1475,7 +1473,7 @@ class Client(object):
|
||||||
request=request
|
request=request
|
||||||
)
|
)
|
||||||
|
|
||||||
class ZulipStream(object):
|
class ZulipStream:
|
||||||
"""
|
"""
|
||||||
A Zulip stream-like object
|
A Zulip stream-like object
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# zulip-send -- Sends a message to the specified recipients.
|
# zulip-send -- Sends a message to the specified recipients.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -23,7 +22,7 @@ if not IS_PYPA_PACKAGE:
|
||||||
package_data[''].append('fixtures/*.json')
|
package_data[''].append('fixtures/*.json')
|
||||||
package_data[''].append('logo.*')
|
package_data[''].append('logo.*')
|
||||||
|
|
||||||
with open("README.md", "r") as fh:
|
with open("README.md") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
# We should be installable with either setuptools or distutils.
|
# We should be installable with either setuptools or distutils.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
from typing import Any, List, Dict
|
from typing import Any, List, Dict
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
class BaremetricsHandler(object):
|
class BaremetricsHandler:
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
self.config_info = bot_handler.get_config_info('baremetrics')
|
self.config_info = bot_handler.get_config_info('baremetrics')
|
||||||
self.api_key = self.config_info['api_key']
|
self.api_key = self.config_info['api_key']
|
||||||
|
|
|
@ -74,7 +74,7 @@ at syntax by: @mention-botname help"
|
||||||
right now.\nPlease try again later"
|
right now.\nPlease try again later"
|
||||||
|
|
||||||
|
|
||||||
class BeeminderHandler(object):
|
class BeeminderHandler:
|
||||||
'''
|
'''
|
||||||
This plugin allows users to easily add datapoints
|
This plugin allows users to easily add datapoints
|
||||||
towards their beeminder goals via zulip
|
towards their beeminder goals via zulip
|
||||||
|
|
|
@ -11,7 +11,7 @@ START_COMPUTER_REGEX = re.compile(
|
||||||
MOVE_REGEX = re.compile('do (?P<move_san>.+)$')
|
MOVE_REGEX = re.compile('do (?P<move_san>.+)$')
|
||||||
RESIGN_REGEX = re.compile('resign$')
|
RESIGN_REGEX = re.compile('resign$')
|
||||||
|
|
||||||
class ChessHandler(object):
|
class ChessHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return (
|
return (
|
||||||
'Chess Bot is a bot that allows you to play chess against either '
|
'Chess Bot is a bot that allows you to play chess against either '
|
||||||
|
@ -742,4 +742,4 @@ def trim_whitespace_before_newline(str_to_trim: str) -> str:
|
||||||
|
|
||||||
Returns: The trimmed string.
|
Returns: The trimmed string.
|
||||||
"""
|
"""
|
||||||
return re.sub('\s+$', '', str_to_trim, flags=re.M)
|
return re.sub(r'\s+$', '', str_to_trim, flags=re.M)
|
||||||
|
|
|
@ -3,7 +3,7 @@ from zulip_bots.bots.connect_four.controller import ConnectFourModel
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class ConnectFourMessageHandler(object):
|
class ConnectFourMessageHandler:
|
||||||
tokens = [':blue_circle:', ':red_circle:']
|
tokens = [':blue_circle:', ':red_circle:']
|
||||||
|
|
||||||
def parse_board(self, board: Any) -> str:
|
def parse_board(self, board: Any) -> str:
|
||||||
|
@ -52,7 +52,7 @@ class ConnectFourBotHandler(GameAdapter):
|
||||||
gameMessageHandler = ConnectFourMessageHandler
|
gameMessageHandler = ConnectFourMessageHandler
|
||||||
rules = '''Try to get four pieces in row, Diagonals count too!'''
|
rules = '''Try to get four pieces in row, Diagonals count too!'''
|
||||||
|
|
||||||
super(ConnectFourBotHandler, self).__init__(
|
super().__init__(
|
||||||
game_name,
|
game_name,
|
||||||
bot_name,
|
bot_name,
|
||||||
move_help_message,
|
move_help_message,
|
||||||
|
|
|
@ -4,7 +4,7 @@ from functools import reduce
|
||||||
from zulip_bots.game_handler import BadMoveException
|
from zulip_bots.game_handler import BadMoveException
|
||||||
|
|
||||||
|
|
||||||
class ConnectFourModel(object):
|
class ConnectFourModel:
|
||||||
'''
|
'''
|
||||||
Object that manages running the Connect
|
Object that manages running the Connect
|
||||||
Four logic for the Connect Four Bot
|
Four logic for the Connect Four Bot
|
||||||
|
|
|
@ -25,7 +25,7 @@ def is_float(value: Any) -> bool:
|
||||||
def round_to(x: float, digits: int) -> float:
|
def round_to(x: float, digits: int) -> float:
|
||||||
return round(x, digits-int(floor(log10(abs(x)))))
|
return round(x, digits-int(floor(log10(abs(x)))))
|
||||||
|
|
||||||
class ConverterHandler(object):
|
class ConverterHandler:
|
||||||
'''
|
'''
|
||||||
This plugin allows users to make conversions between various units,
|
This plugin allows users to make conversions between various units,
|
||||||
e.g. Celsius to Fahrenheit, or kilobytes to gigabytes.
|
e.g. Celsius to Fahrenheit, or kilobytes to gigabytes.
|
||||||
|
|
|
@ -7,7 +7,7 @@ import string
|
||||||
|
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
class DefineHandler(object):
|
class DefineHandler:
|
||||||
'''
|
'''
|
||||||
This plugin define a word that the user inputs. It
|
This plugin define a word that the user inputs. It
|
||||||
looks for messages starting with '@mention-bot'.
|
looks for messages starting with '@mention-bot'.
|
||||||
|
|
|
@ -35,7 +35,7 @@ def get_bot_result(message_content: str, config: Dict[str, str], sender_id: str)
|
||||||
logging.exception(str(e))
|
logging.exception(str(e))
|
||||||
return 'Error. {}.'.format(str(e))
|
return 'Error. {}.'.format(str(e))
|
||||||
|
|
||||||
class DialogFlowHandler(object):
|
class DialogFlowHandler:
|
||||||
'''
|
'''
|
||||||
This plugin allows users to easily add their own
|
This plugin allows users to easily add their own
|
||||||
DialogFlow bots to zulip
|
DialogFlow bots to zulip
|
||||||
|
|
|
@ -4,7 +4,7 @@ import re
|
||||||
|
|
||||||
URL = "[{name}](https://www.dropbox.com/home{path})"
|
URL = "[{name}](https://www.dropbox.com/home{path})"
|
||||||
|
|
||||||
class DropboxHandler(object):
|
class DropboxHandler:
|
||||||
'''
|
'''
|
||||||
This bot allows you to easily share, search and upload files
|
This bot allows you to easily share, search and upload files
|
||||||
between zulip and your dropbox account.
|
between zulip and your dropbox account.
|
||||||
|
@ -60,11 +60,11 @@ def get_usage_examples() -> str:
|
||||||
|
|
||||||
REGEXES = dict(
|
REGEXES = dict(
|
||||||
command='(ls|mkdir|read|rm|write|search|usage|help)',
|
command='(ls|mkdir|read|rm|write|search|usage|help)',
|
||||||
path='(\S+)',
|
path=r'(\S+)',
|
||||||
optional_path='(\S*)',
|
optional_path=r'(\S*)',
|
||||||
some_text='(.+?)',
|
some_text='(.+?)',
|
||||||
folder='?(?:--fd (\S+))?',
|
folder=r'?(?:--fd (\S+))?',
|
||||||
max_results='?(?:--mr (\d+))?'
|
max_results=r'?(?:--mr (\d+))?'
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_commands() -> Dict[str, Tuple[Any, List[str]]]:
|
def get_commands() -> Dict[str, Tuple[Any, List[str]]]:
|
||||||
|
@ -137,7 +137,7 @@ def dbx_ls(client: Any, fn: str) -> str:
|
||||||
files_list += [" - " + URL.format(name=meta.name, path=meta.path_lower)]
|
files_list += [" - " + URL.format(name=meta.name, path=meta.path_lower)]
|
||||||
|
|
||||||
msg = '\n'.join(files_list)
|
msg = '\n'.join(files_list)
|
||||||
if msg is '':
|
if msg == '':
|
||||||
msg = '`No files available`'
|
msg = '`No files available`'
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -17,7 +17,7 @@ def encrypt(text: str) -> str:
|
||||||
|
|
||||||
return newtext
|
return newtext
|
||||||
|
|
||||||
class EncryptHandler(object):
|
class EncryptHandler:
|
||||||
'''
|
'''
|
||||||
This bot allows users to quickly encrypt messages using ROT13 encryption.
|
This bot allows users to quickly encrypt messages using ROT13 encryption.
|
||||||
It encrypts/decrypts messages starting with @mention-bot.
|
It encrypts/decrypts messages starting with @mention-bot.
|
||||||
|
|
|
@ -3,7 +3,7 @@ from typing import Any, Dict
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
class FileUploaderHandler(object):
|
class FileUploaderHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return (
|
return (
|
||||||
'This interactive bot is used to upload files (such as images) to the Zulip server:'
|
'This interactive bot is used to upload files (such as images) to the Zulip server:'
|
||||||
|
|
|
@ -86,7 +86,7 @@ def get_flock_bot_response(content: str, config: Dict[str, str]) -> None:
|
||||||
result = get_flock_response(content, config)
|
result = get_flock_response(content, config)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class FlockHandler(object):
|
class FlockHandler:
|
||||||
'''
|
'''
|
||||||
This is flock bot. Now you can send messages to any of your
|
This is flock bot. Now you can send messages to any of your
|
||||||
flock user without having to leave Zulip.
|
flock user without having to leave Zulip.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# See readme.md for instructions on running this code.
|
# See readme.md for instructions on running this code.
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
class FollowupHandler(object):
|
class FollowupHandler:
|
||||||
'''
|
'''
|
||||||
This plugin facilitates creating follow-up tasks when
|
This plugin facilitates creating follow-up tasks when
|
||||||
you are using Zulip to conduct a virtual meeting. It
|
you are using Zulip to conduct a virtual meeting. It
|
||||||
|
|
|
@ -2,7 +2,7 @@ import requests
|
||||||
import re
|
import re
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
class FrontHandler(object):
|
class FrontHandler:
|
||||||
FRONT_API = "https://api2.frontapp.com/conversations/{}"
|
FRONT_API = "https://api2.frontapp.com/conversations/{}"
|
||||||
COMMANDS = [
|
COMMANDS = [
|
||||||
('archive', "Archive a conversation."),
|
('archive', "Archive a conversation."),
|
||||||
|
|
|
@ -2,7 +2,7 @@ from zulip_bots.game_handler import GameAdapter, BadMoveException
|
||||||
from typing import List, Any
|
from typing import List, Any
|
||||||
|
|
||||||
|
|
||||||
class GameHandlerBotMessageHandler(object):
|
class GameHandlerBotMessageHandler:
|
||||||
tokens = [':blue_circle:', ':red_circle:']
|
tokens = [':blue_circle:', ':red_circle:']
|
||||||
|
|
||||||
def parse_board(self, board: Any) -> str:
|
def parse_board(self, board: Any) -> str:
|
||||||
|
@ -21,7 +21,7 @@ The first player to get 4 in a row wins!\n \
|
||||||
Good Luck!'
|
Good Luck!'
|
||||||
|
|
||||||
|
|
||||||
class MockModel(object):
|
class MockModel:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.current_board = 'mock board'
|
self.current_board = 'mock board'
|
||||||
|
|
||||||
|
@ -53,12 +53,12 @@ class GameHandlerBotHandler(GameAdapter):
|
||||||
bot_name = 'game_handler_bot'
|
bot_name = 'game_handler_bot'
|
||||||
move_help_message = '* To make your move during a game, type\n' \
|
move_help_message = '* To make your move during a game, type\n' \
|
||||||
'```move <column-number>```'
|
'```move <column-number>```'
|
||||||
move_regex = 'move (\d)$'
|
move_regex = r'move (\d)$'
|
||||||
model = MockModel
|
model = MockModel
|
||||||
gameMessageHandler = GameHandlerBotMessageHandler
|
gameMessageHandler = GameHandlerBotMessageHandler
|
||||||
rules = ''
|
rules = ''
|
||||||
|
|
||||||
super(GameHandlerBotHandler, self).__init__(
|
super().__init__(
|
||||||
game_name,
|
game_name,
|
||||||
bot_name,
|
bot_name,
|
||||||
move_help_message,
|
move_help_message,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import random
|
||||||
from typing import List, Any, Tuple, Dict
|
from typing import List, Any, Tuple, Dict
|
||||||
from zulip_bots.game_handler import GameAdapter, BadMoveException
|
from zulip_bots.game_handler import GameAdapter, BadMoveException
|
||||||
|
|
||||||
class GameOfFifteenModel(object):
|
class GameOfFifteenModel:
|
||||||
|
|
||||||
final_board = [[0, 1, 2],
|
final_board = [[0, 1, 2],
|
||||||
[3, 4, 5],
|
[3, 4, 5],
|
||||||
|
@ -84,7 +84,7 @@ class GameOfFifteenModel(object):
|
||||||
if m == moves - 1:
|
if m == moves - 1:
|
||||||
return board
|
return board
|
||||||
|
|
||||||
class GameOfFifteenMessageHandler(object):
|
class GameOfFifteenMessageHandler:
|
||||||
|
|
||||||
tiles = {
|
tiles = {
|
||||||
'0': ':grey_question:',
|
'0': ':grey_question:',
|
||||||
|
@ -127,14 +127,14 @@ class GameOfFifteenBotHandler(GameAdapter):
|
||||||
bot_name = 'Game of Fifteen'
|
bot_name = 'Game of Fifteen'
|
||||||
move_help_message = '* To make your move during a game, type\n' \
|
move_help_message = '* To make your move during a game, type\n' \
|
||||||
'```move <tile1> <tile2> ...```'
|
'```move <tile1> <tile2> ...```'
|
||||||
move_regex = 'move [\d{1}\s]+$'
|
move_regex = r'move [\d{1}\s]+$'
|
||||||
model = GameOfFifteenModel
|
model = GameOfFifteenModel
|
||||||
gameMessageHandler = GameOfFifteenMessageHandler
|
gameMessageHandler = GameOfFifteenMessageHandler
|
||||||
rules = '''Arrange the board’s tiles from smallest to largest, left to right,
|
rules = '''Arrange the board’s tiles from smallest to largest, left to right,
|
||||||
top to bottom, and tiles adjacent to :grey_question: can only be moved.
|
top to bottom, and tiles adjacent to :grey_question: can only be moved.
|
||||||
Final configuration will have :grey_question: in top left.'''
|
Final configuration will have :grey_question: in top left.'''
|
||||||
|
|
||||||
super(GameOfFifteenBotHandler, self).__init__(
|
super().__init__(
|
||||||
game_name,
|
game_name,
|
||||||
bot_name,
|
bot_name,
|
||||||
move_help_message,
|
move_help_message,
|
||||||
|
|
|
@ -9,7 +9,7 @@ GIPHY_TRANSLATE_API = 'http://api.giphy.com/v1/gifs/translate'
|
||||||
GIPHY_RANDOM_API = 'http://api.giphy.com/v1/gifs/random'
|
GIPHY_RANDOM_API = 'http://api.giphy.com/v1/gifs/random'
|
||||||
|
|
||||||
|
|
||||||
class GiphyHandler(object):
|
class GiphyHandler:
|
||||||
"""
|
"""
|
||||||
This plugin posts a GIF in response to the keywords provided by the user.
|
This plugin posts a GIF in response to the keywords provided by the user.
|
||||||
Images are provided by Giphy, through the public API.
|
Images are provided by Giphy, through the public API.
|
||||||
|
|
|
@ -8,14 +8,14 @@ import requests
|
||||||
|
|
||||||
from typing import Dict, Any, Tuple, Union
|
from typing import Dict, Any, Tuple, Union
|
||||||
|
|
||||||
class GithubHandler(object):
|
class GithubHandler:
|
||||||
'''
|
'''
|
||||||
This bot provides details on github issues and pull requests when they're
|
This bot provides details on github issues and pull requests when they're
|
||||||
referenced in the chat.
|
referenced in the chat.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
GITHUB_ISSUE_URL_TEMPLATE = 'https://api.github.com/repos/{owner}/{repo}/issues/{id}'
|
GITHUB_ISSUE_URL_TEMPLATE = 'https://api.github.com/repos/{owner}/{repo}/issues/{id}'
|
||||||
HANDLE_MESSAGE_REGEX = re.compile("(?:([\w-]+)\/)?([\w-]+)?#(\d+)")
|
HANDLE_MESSAGE_REGEX = re.compile(r"(?:([\w-]+)\/)?([\w-]+)?#(\d+)")
|
||||||
|
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
self.config_info = bot_handler.get_config_info('github_detail', optional=True)
|
self.config_info = bot_handler.get_config_info('github_detail', optional=True)
|
||||||
|
|
|
@ -63,7 +63,7 @@ def get_google_result(search_keywords: str) -> str:
|
||||||
logging.exception(str(e))
|
logging.exception(str(e))
|
||||||
return 'Error: Search failed. {}.'.format(e)
|
return 'Error: Search failed. {}.'.format(e)
|
||||||
|
|
||||||
class GoogleSearchHandler(object):
|
class GoogleSearchHandler:
|
||||||
'''
|
'''
|
||||||
This plugin allows users to enter a search
|
This plugin allows users to enter a search
|
||||||
term in Zulip and get the top URL sent back
|
term in Zulip and get the top URL sent back
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import requests
|
import requests
|
||||||
from requests.exceptions import HTTPError, ConnectionError
|
from requests.exceptions import HTTPError, ConnectionError
|
||||||
|
|
||||||
class GoogleTranslateHandler(object):
|
class GoogleTranslateHandler:
|
||||||
'''
|
'''
|
||||||
This bot will translate any messages sent to it using google translate.
|
This bot will translate any messages sent to it using google translate.
|
||||||
Before using it, make sure you set up google api keys, and enable google
|
Before using it, make sure you set up google api keys, and enable google
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
class HelloWorldHandler(object):
|
class HelloWorldHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return '''
|
return '''
|
||||||
This is a boilerplate bot that responds to a user query with
|
This is a boilerplate bot that responds to a user query with
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# See readme.md for instructions on running this code.
|
# See readme.md for instructions on running this code.
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
class HelpHandler(object):
|
class HelpHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return '''
|
return '''
|
||||||
This plugin will give info about Zulip to
|
This plugin will give info about Zulip to
|
||||||
|
|
|
@ -128,7 +128,7 @@ More information in my help""")
|
||||||
data = api_create_entry(new_message, team_id)
|
data = api_create_entry(new_message, team_id)
|
||||||
return "Great work :thumbs_up:. New entry `{}` created!".format(data['body_formatted'])
|
return "Great work :thumbs_up:. New entry `{}` created!".format(data['body_formatted'])
|
||||||
|
|
||||||
class IDoneThisHandler(object):
|
class IDoneThisHandler:
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
global api_key, default_team
|
global api_key, default_team
|
||||||
self.config_info = bot_handler.get_config_info('idonethis')
|
self.config_info = bot_handler.get_config_info('idonethis')
|
||||||
|
|
|
@ -59,7 +59,7 @@ def start_new_incident(query: str, message: Dict[str, Any], bot_handler: Any) ->
|
||||||
bot_handler.send_reply(message, bot_response, widget_content)
|
bot_handler.send_reply(message, bot_response, widget_content)
|
||||||
|
|
||||||
def parse_answer(query: str) -> Tuple[str, str]:
|
def parse_answer(query: str) -> Tuple[str, str]:
|
||||||
m = re.match('answer\s+(TICKET....)\s+(.)', query)
|
m = re.match(r'answer\s+(TICKET....)\s+(.)', query)
|
||||||
if not m:
|
if not m:
|
||||||
raise InvalidAnswerException()
|
raise InvalidAnswerException()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
class IncrementorHandler(object):
|
class IncrementorHandler:
|
||||||
META = {
|
META = {
|
||||||
'name': 'Incrementor',
|
'name': 'Incrementor',
|
||||||
'description': 'Example bot to test the update_message() function.',
|
'description': 'Example bot to test the update_message() function.',
|
||||||
|
|
|
@ -106,7 +106,7 @@ Jira Bot:
|
||||||
> Issue *BOTS-16* was edited! https://example.atlassian.net/browse/BOTS-16
|
> Issue *BOTS-16* was edited! https://example.atlassian.net/browse/BOTS-16
|
||||||
'''
|
'''
|
||||||
|
|
||||||
class JiraHandler(object):
|
class JiraHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return '''
|
return '''
|
||||||
Jira Bot uses the Jira REST API to interact with Jira. In order to use
|
Jira Bot uses the Jira REST API to interact with Jira. In order to use
|
||||||
|
@ -164,14 +164,14 @@ class JiraHandler(object):
|
||||||
response = 'Oh no! Jira raised an error:\n > ' + ', '.join(errors)
|
response = 'Oh no! Jira raised an error:\n > ' + ', '.join(errors)
|
||||||
else:
|
else:
|
||||||
response = (
|
response = (
|
||||||
'**Issue *[{0}]({1})*: {2}**\n\n'
|
'**Issue *[{}]({})*: {}**\n\n'
|
||||||
' - Type: *{3}*\n'
|
' - Type: *{}*\n'
|
||||||
' - Description:\n'
|
' - Description:\n'
|
||||||
' > {4}\n'
|
' > {}\n'
|
||||||
' - Creator: *{5}*\n'
|
' - Creator: *{}*\n'
|
||||||
' - Project: *{6}*\n'
|
' - Project: *{}*\n'
|
||||||
' - Priority: *{7}*\n'
|
' - Priority: *{}*\n'
|
||||||
' - Status: *{8}*\n'
|
' - Status: *{}*\n'
|
||||||
).format(key, url, summary, type_name, description, creator_name, project_name,
|
).format(key, url, summary, type_name, description, creator_name, project_name,
|
||||||
priority_name, status_name)
|
priority_name, status_name)
|
||||||
elif create_match:
|
elif create_match:
|
||||||
|
|
|
@ -4,7 +4,7 @@ import logging
|
||||||
|
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
class LinkShortenerHandler(object):
|
class LinkShortenerHandler:
|
||||||
'''A Zulip bot that will shorten URLs ("links") in a conversation using the
|
'''A Zulip bot that will shorten URLs ("links") in a conversation using the
|
||||||
goo.gl URL shortener.
|
goo.gl URL shortener.
|
||||||
'''
|
'''
|
||||||
|
@ -33,10 +33,10 @@ class LinkShortenerHandler(object):
|
||||||
def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
|
def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
|
||||||
REGEX_STR = (
|
REGEX_STR = (
|
||||||
'('
|
'('
|
||||||
'(?:http|https):\/\/' # This allows for the HTTP or HTTPS
|
r'(?:http|https):\/\/' # This allows for the HTTP or HTTPS
|
||||||
# protocol.
|
# protocol.
|
||||||
'[^"<>\{\}|\\^~[\]` ]+' # This allows for any character except
|
'[^"<>\\{\\}|\\^~[\\]` ]+' # This allows for any character except
|
||||||
# for certain non-URL-safe ones.
|
# for certain non-URL-safe ones.
|
||||||
')'
|
')'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import requests
|
||||||
from typing import Any, List, Dict
|
from typing import Any, List, Dict
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
class MentionHandler(object):
|
class MentionHandler:
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
self.config_info = bot_handler.get_config_info('mention')
|
self.config_info = bot_handler.get_config_info('mention')
|
||||||
self.access_token = self.config_info['access_token']
|
self.access_token = self.config_info['access_token']
|
||||||
|
|
|
@ -199,5 +199,5 @@ def check_win(topic_name, merels_storage):
|
||||||
win = mechanics.who_won(topic_name, merels_storage)
|
win = mechanics.who_won(topic_name, merels_storage)
|
||||||
if win != "None":
|
if win != "None":
|
||||||
merels.remove_game(topic_name)
|
merels.remove_game(topic_name)
|
||||||
return "{0} wins the game!".format(win)
|
return "{} wins the game!".format(win)
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -285,7 +285,7 @@ def create_room(topic_name, merels_storage):
|
||||||
|
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return "Failed: Cannot create an already existing game in {0}. " \
|
return "Failed: Cannot create an already existing game in {}. " \
|
||||||
"Please finish the game first.".format(topic_name)
|
"Please finish the game first.".format(topic_name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ def move_man(topic_name, p1, p2, merels_storage):
|
||||||
merels.update_game(data.topic_name, data.turn, data.x_taken,
|
merels.update_game(data.topic_name, data.turn, data.x_taken,
|
||||||
data.o_taken, data.board, data.hill_uid,
|
data.o_taken, data.board, data.hill_uid,
|
||||||
data.take_mode)
|
data.take_mode)
|
||||||
return "Moved a man from ({0}, {1}) -> ({2}, {3}) for {4}.".format(
|
return "Moved a man from ({}, {}) -> ({}, {}) for {}.".format(
|
||||||
p1[0], p1[1], p2[0], p2[1], data.turn)
|
p1[0], p1[1], p2[0], p2[1], data.turn)
|
||||||
else:
|
else:
|
||||||
raise BadMoveException("Failed: That's not a legal move. Please try again.")
|
raise BadMoveException("Failed: That's not a legal move. Please try again.")
|
||||||
|
@ -390,7 +390,7 @@ def put_man(topic_name, v, h, merels_storage):
|
||||||
merels.update_game(data.topic_name, data.turn, data.x_taken,
|
merels.update_game(data.topic_name, data.turn, data.x_taken,
|
||||||
data.o_taken, data.board, data.hill_uid,
|
data.o_taken, data.board, data.hill_uid,
|
||||||
data.take_mode)
|
data.take_mode)
|
||||||
return "Put a man to ({0}, {1}) for {2}.".format(v, h, data.turn)
|
return "Put a man to ({}, {}) for {}.".format(v, h, data.turn)
|
||||||
else:
|
else:
|
||||||
raise BadMoveException("Failed: That's not a legal put. Please try again.")
|
raise BadMoveException("Failed: That's not a legal put. Please try again.")
|
||||||
|
|
||||||
|
@ -428,7 +428,7 @@ def take_man(topic_name, v, h, merels_storage):
|
||||||
merels.update_game(data.topic_name, data.turn, data.x_taken,
|
merels.update_game(data.topic_name, data.turn, data.x_taken,
|
||||||
data.o_taken, data.board, data.hill_uid,
|
data.o_taken, data.board, data.hill_uid,
|
||||||
data.take_mode)
|
data.take_mode)
|
||||||
return "Taken a man from ({0}, {1}) for {2}.".format(v, h, data.turn)
|
return "Taken a man from ({}, {}) for {}.".format(v, h, data.turn)
|
||||||
else:
|
else:
|
||||||
raise BadMoveException("Failed: That's not a legal take. Please try again.")
|
raise BadMoveException("Failed: That's not a legal take. Please try again.")
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from zulip_bots.bots.merels.libraries import (
|
||||||
)
|
)
|
||||||
from zulip_bots.game_handler import GameAdapter, SamePlayerMove, GameInstance
|
from zulip_bots.game_handler import GameAdapter, SamePlayerMove, GameInstance
|
||||||
|
|
||||||
class Storage(object):
|
class Storage:
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
def __init__(self, topic_name):
|
def __init__(self, topic_name):
|
||||||
|
@ -19,7 +19,7 @@ class Storage(object):
|
||||||
def get(self, topic_name):
|
def get(self, topic_name):
|
||||||
return self.data[topic_name]
|
return self.data[topic_name]
|
||||||
|
|
||||||
class MerelsModel(object):
|
class MerelsModel:
|
||||||
|
|
||||||
def __init__(self, board: Any=None) -> None:
|
def __init__(self, board: Any=None) -> None:
|
||||||
self.topic = "merels"
|
self.topic = "merels"
|
||||||
|
@ -54,7 +54,7 @@ class MerelsModel(object):
|
||||||
raise SamePlayerMove(same_player_move)
|
raise SamePlayerMove(same_player_move)
|
||||||
return self.current_board
|
return self.current_board
|
||||||
|
|
||||||
class MerelsMessageHandler(object):
|
class MerelsMessageHandler:
|
||||||
tokens = [':o_button:', ':cross_mark_button:']
|
tokens = [':o_button:', ':cross_mark_button:']
|
||||||
|
|
||||||
def parse_board(self, board: Any) -> str:
|
def parse_board(self, board: Any) -> str:
|
||||||
|
@ -90,7 +90,7 @@ class MerelsHandler(GameAdapter):
|
||||||
model = MerelsModel
|
model = MerelsModel
|
||||||
rules = game.getInfo()
|
rules = game.getInfo()
|
||||||
gameMessageHandler = MerelsMessageHandler
|
gameMessageHandler = MerelsMessageHandler
|
||||||
super(MerelsHandler, self).__init__(
|
super().__init__(
|
||||||
game_name,
|
game_name,
|
||||||
bot_name,
|
bot_name,
|
||||||
move_help_message,
|
move_help_message,
|
||||||
|
|
|
@ -5,7 +5,7 @@ from zulip_bots.bots.monkeytestit.lib import parse
|
||||||
from zulip_bots.lib import NoBotConfigException
|
from zulip_bots.lib import NoBotConfigException
|
||||||
|
|
||||||
|
|
||||||
class MonkeyTestitBot(object):
|
class MonkeyTestitBot:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_key = "None"
|
self.api_key = "None"
|
||||||
self.config = None
|
self.config = None
|
||||||
|
|
|
@ -82,7 +82,7 @@ def query_salesforce(arg: str, salesforce: simple_salesforce.Salesforce, command
|
||||||
raw_arg = ' -' + arg.split(' -', 1)[1]
|
raw_arg = ' -' + arg.split(' -', 1)[1]
|
||||||
split_args = raw_arg.split(' -')
|
split_args = raw_arg.split(' -')
|
||||||
limit_num = 5
|
limit_num = 5
|
||||||
re_limit = re.compile('-limit \d+')
|
re_limit = re.compile(r'-limit \d+')
|
||||||
limit = re_limit.search(raw_arg)
|
limit = re_limit.search(raw_arg)
|
||||||
if limit:
|
if limit:
|
||||||
limit_num = int(limit.group().rsplit(' ', 1)[1])
|
limit_num = int(limit.group().rsplit(' ', 1)[1])
|
||||||
|
@ -122,7 +122,7 @@ def get_salesforce_link_details(link: str, sf: Any) -> str:
|
||||||
return 'No object found. Make sure it is of the supported types. Type `help` for more info.'
|
return 'No object found. Make sure it is of the supported types. Type `help` for more info.'
|
||||||
|
|
||||||
|
|
||||||
class SalesforceHandler(object):
|
class SalesforceHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return '''
|
return '''
|
||||||
This is a Salesforce bot, which can search for Contacts,
|
This is a Salesforce bot, which can search for Contacts,
|
||||||
|
@ -136,7 +136,7 @@ class SalesforceHandler(object):
|
||||||
|
|
||||||
def get_salesforce_response(self, content: str) -> str:
|
def get_salesforce_response(self, content: str) -> str:
|
||||||
content = content.strip()
|
content = content.strip()
|
||||||
if content is '' or content == 'help':
|
if content == '' or content == 'help':
|
||||||
return get_help_text()
|
return get_help_text()
|
||||||
if content.startswith('http') and 'force' in content:
|
if content.startswith('http') and 'force' in content:
|
||||||
return get_salesforce_link_details(content, self.sf)
|
return get_salesforce_link_details(content, self.sf)
|
||||||
|
|
|
@ -7,7 +7,7 @@ from typing import Optional, Any, Dict
|
||||||
|
|
||||||
# See readme.md for instructions on running this code.
|
# See readme.md for instructions on running this code.
|
||||||
|
|
||||||
class StackOverflowHandler(object):
|
class StackOverflowHandler:
|
||||||
'''
|
'''
|
||||||
This plugin facilitates searching Stack Overflow for a
|
This plugin facilitates searching Stack Overflow for a
|
||||||
specific query and returns the top 3 questions from the
|
specific query and returns the top 3 questions from the
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import requests
|
import requests
|
||||||
from typing import Dict, Any, Tuple, Union
|
from typing import Dict, Any, Tuple, Union
|
||||||
|
|
||||||
class SusiHandler(object):
|
class SusiHandler:
|
||||||
'''
|
'''
|
||||||
Susi AI Bot
|
Susi AI Bot
|
||||||
To create and know more of SUSI skills go to `https://skills.susi.ai/`
|
To create and know more of SUSI skills go to `https://skills.susi.ai/`
|
||||||
|
|
|
@ -9,7 +9,7 @@ from zulip_bots.game_handler import GameAdapter, BadMoveException
|
||||||
State = List[List[str]]
|
State = List[List[str]]
|
||||||
|
|
||||||
|
|
||||||
class TicTacToeModel(object):
|
class TicTacToeModel:
|
||||||
smarter = True
|
smarter = True
|
||||||
# If smarter is True, the computer will do some extra thinking - it'll be harder for the user.
|
# If smarter is True, the computer will do some extra thinking - it'll be harder for the user.
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ class TicTacToeModel(object):
|
||||||
return board
|
return board
|
||||||
|
|
||||||
|
|
||||||
class TicTacToeMessageHandler(object):
|
class TicTacToeMessageHandler:
|
||||||
tokens = [':x:', ':o:']
|
tokens = [':x:', ':o:']
|
||||||
|
|
||||||
def parse_row(self, row: Tuple[int, int], row_num: int) -> str:
|
def parse_row(self, row: Tuple[int, int], row_num: int) -> str:
|
||||||
|
@ -259,11 +259,11 @@ class ticTacToeHandler(GameAdapter):
|
||||||
game_name = 'Tic Tac Toe'
|
game_name = 'Tic Tac Toe'
|
||||||
bot_name = 'tictactoe'
|
bot_name = 'tictactoe'
|
||||||
move_help_message = '* To move during a game, type\n`move <number>` or `<number>`'
|
move_help_message = '* To move during a game, type\n`move <number>` or `<number>`'
|
||||||
move_regex = '(move (\d)$)|((\d)$)'
|
move_regex = r'(move (\d)$)|((\d)$)'
|
||||||
model = TicTacToeModel
|
model = TicTacToeModel
|
||||||
gameMessageHandler = TicTacToeMessageHandler
|
gameMessageHandler = TicTacToeMessageHandler
|
||||||
rules = '''Try to get three in horizontal or vertical or diagonal row to win the game.'''
|
rules = '''Try to get three in horizontal or vertical or diagonal row to win the game.'''
|
||||||
super(ticTacToeHandler, self).__init__(
|
super().__init__(
|
||||||
game_name,
|
game_name,
|
||||||
bot_name,
|
bot_name,
|
||||||
move_help_message,
|
move_help_message,
|
||||||
|
|
|
@ -14,7 +14,7 @@ supported_commands = [
|
||||||
INVALID_ARGUMENTS_ERROR_MESSAGE = 'Invalid Arguments.'
|
INVALID_ARGUMENTS_ERROR_MESSAGE = 'Invalid Arguments.'
|
||||||
RESPONSE_ERROR_MESSAGE = 'Invalid Response. Please check configuration and parameters.'
|
RESPONSE_ERROR_MESSAGE = 'Invalid Response. Please check configuration and parameters.'
|
||||||
|
|
||||||
class TrelloHandler(object):
|
class TrelloHandler:
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
self.config_info = bot_handler.get_config_info('trello')
|
self.config_info = bot_handler.get_config_info('trello')
|
||||||
self.api_key = self.config_info['api_key']
|
self.api_key = self.config_info['api_key']
|
||||||
|
|
|
@ -65,7 +65,7 @@ def start_new_quiz(message: Dict[str, Any], bot_handler: Any) -> None:
|
||||||
bot_handler.send_reply(message, bot_response, widget_content)
|
bot_handler.send_reply(message, bot_response, widget_content)
|
||||||
|
|
||||||
def parse_answer(query: str) -> Tuple[str, str]:
|
def parse_answer(query: str) -> Tuple[str, str]:
|
||||||
m = re.match('answer\s+(Q...)\s+(.)', query)
|
m = re.match(r'answer\s+(Q...)\s+(.)', query)
|
||||||
if not m:
|
if not m:
|
||||||
raise InvalidAnswerException()
|
raise InvalidAnswerException()
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import tweepy
|
||||||
from typing import Dict, Any, Union, List, Tuple, Optional
|
from typing import Dict, Any, Union, List, Tuple, Optional
|
||||||
|
|
||||||
|
|
||||||
class TwitpostBot(object):
|
class TwitpostBot:
|
||||||
|
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return ''' This bot posts on twitter from zulip chat itself.
|
return ''' This bot posts on twitter from zulip chat itself.
|
||||||
|
|
|
@ -5,7 +5,7 @@ import os
|
||||||
|
|
||||||
from typing import Any, Dict, List, Tuple, Callable, Set, Union
|
from typing import Any, Dict, List, Tuple, Callable, Set, Union
|
||||||
|
|
||||||
class VirtualFsHandler(object):
|
class VirtualFsHandler:
|
||||||
META = {
|
META = {
|
||||||
'name': 'VirtualFs',
|
'name': 'VirtualFs',
|
||||||
'description': 'Provides a simple, permanent file system to store and retrieve strings.',
|
'description': 'Provides a simple, permanent file system to store and retrieve strings.',
|
||||||
|
@ -112,8 +112,8 @@ def sample_conversation() -> List[Tuple[str, str]]:
|
||||||
|
|
||||||
REGEXES = dict(
|
REGEXES = dict(
|
||||||
command='(cd|ls|mkdir|read|rmdir|rm|write|pwd)',
|
command='(cd|ls|mkdir|read|rmdir|rm|write|pwd)',
|
||||||
path='(\S+)',
|
path=r'(\S+)',
|
||||||
optional_path='(\S*)',
|
optional_path=r'(\S*)',
|
||||||
some_text='(.+)',
|
some_text='(.+)',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from typing import Any, Dict
|
||||||
|
|
||||||
api_url = 'http://api.openweathermap.org/data/2.5/weather'
|
api_url = 'http://api.openweathermap.org/data/2.5/weather'
|
||||||
|
|
||||||
class WeatherHandler(object):
|
class WeatherHandler:
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
self.api_key = bot_handler.get_config_info('weather')['key']
|
self.api_key = bot_handler.get_config_info('weather')['key']
|
||||||
self.response_pattern = 'Weather in {}, {}:\n{:.2f} F / {:.2f} C\n{}'
|
self.response_pattern = 'Weather in {}, {}:\n{:.2f} F / {:.2f} C\n{}'
|
||||||
|
|
|
@ -8,7 +8,7 @@ from typing import Optional, Any, Dict
|
||||||
|
|
||||||
# See readme.md for instructions on running this code.
|
# See readme.md for instructions on running this code.
|
||||||
|
|
||||||
class WikipediaHandler(object):
|
class WikipediaHandler:
|
||||||
'''
|
'''
|
||||||
This plugin facilitates searching Wikipedia for a
|
This plugin facilitates searching Wikipedia for a
|
||||||
specific key term and returns the top 3 articles from the
|
specific key term and returns the top 3 articles from the
|
||||||
|
|
|
@ -5,7 +5,7 @@ import wit
|
||||||
import sys
|
import sys
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
||||||
class WitaiHandler(object):
|
class WitaiHandler:
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return '''
|
return '''
|
||||||
Wit.ai bot uses pywit API to interact with Wit.ai. In order to use
|
Wit.ai bot uses pywit API to interact with Wit.ai. In order to use
|
||||||
|
|
|
@ -8,7 +8,7 @@ from typing import Any, Dict, Optional
|
||||||
XKCD_TEMPLATE_URL = 'https://xkcd.com/%s/info.0.json'
|
XKCD_TEMPLATE_URL = 'https://xkcd.com/%s/info.0.json'
|
||||||
LATEST_XKCD_URL = 'https://xkcd.com/info.0.json'
|
LATEST_XKCD_URL = 'https://xkcd.com/info.0.json'
|
||||||
|
|
||||||
class XkcdHandler(object):
|
class XkcdHandler:
|
||||||
'''
|
'''
|
||||||
This plugin provides several commands that can be used for fetch a comic
|
This plugin provides several commands that can be used for fetch a comic
|
||||||
strip from https://xkcd.com. The bot looks for messages starting with
|
strip from https://xkcd.com. The bot looks for messages starting with
|
||||||
|
@ -39,7 +39,7 @@ class XkcdHandler(object):
|
||||||
xkcd_bot_response = get_xkcd_bot_response(message, quoted_name)
|
xkcd_bot_response = get_xkcd_bot_response(message, quoted_name)
|
||||||
bot_handler.send_reply(message, xkcd_bot_response)
|
bot_handler.send_reply(message, xkcd_bot_response)
|
||||||
|
|
||||||
class XkcdBotCommand(object):
|
class XkcdBotCommand:
|
||||||
LATEST = 0
|
LATEST = 0
|
||||||
RANDOM = 1
|
RANDOM = 1
|
||||||
COMIC_ID = 2
|
COMIC_ID = 2
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ServiceUnavailableError(Exception):
|
||||||
'''raise this when the service is unavailable.'''
|
'''raise this when the service is unavailable.'''
|
||||||
|
|
||||||
|
|
||||||
class YodaSpeakHandler(object):
|
class YodaSpeakHandler:
|
||||||
'''
|
'''
|
||||||
This bot will allow users to translate a sentence into 'Yoda speak'.
|
This bot will allow users to translate a sentence into 'Yoda speak'.
|
||||||
It looks for messages starting with '@mention-bot'.
|
It looks for messages starting with '@mention-bot'.
|
||||||
|
|
|
@ -7,7 +7,7 @@ from typing import Dict, Any, Union, List, Tuple, Optional
|
||||||
|
|
||||||
commands_list = ('list', 'top', 'help')
|
commands_list = ('list', 'top', 'help')
|
||||||
|
|
||||||
class YoutubeHandler(object):
|
class YoutubeHandler:
|
||||||
|
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return '''
|
return '''
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue