black: Reformat without skipping string normalization.

This commit is contained in:
PIG208 2021-05-28 17:05:11 +08:00 committed by Tim Abbott
parent fba21bb00d
commit 6f3f9bf7e4
178 changed files with 5242 additions and 5242 deletions

View file

@ -71,10 +71,10 @@ if __name__ == "__main__":
all topics within the stream are mirrored as-is without
translation.
"""
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
parser = argparse.ArgumentParser(usage=usage)
parser.add_argument('--stream', action='store_true', help="", default=False)
parser.add_argument("--stream", action="store_true", help="", default=False)
args = parser.parse_args()
options = interrealm_bridge_config.config

View file

@ -29,13 +29,13 @@ if __name__ == "__main__":
parser = zulip.add_default_arguments(
argparse.ArgumentParser(usage=usage), allow_provisioning=True
)
parser.add_argument('--irc-server', default=None)
parser.add_argument('--port', default=6667)
parser.add_argument('--nick-prefix', default=None)
parser.add_argument('--channel', default=None)
parser.add_argument('--stream', default="general")
parser.add_argument('--topic', default="IRC")
parser.add_argument('--nickserv-pw', default='')
parser.add_argument("--irc-server", default=None)
parser.add_argument("--port", default=6667)
parser.add_argument("--nick-prefix", default=None)
parser.add_argument("--channel", default=None)
parser.add_argument("--stream", default="general")
parser.add_argument("--topic", default="IRC")
parser.add_argument("--nickserv-pw", default="")
options = parser.parse_args()
# Setting the client to irc_mirror is critical for this to work

View file

@ -18,7 +18,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
channel: irc.bot.Channel,
nickname: str,
server: str,
nickserv_password: str = '',
nickserv_password: str = "",
port: int = 6667,
) -> None:
self.channel = channel # type: irc.bot.Channel
@ -61,8 +61,8 @@ class IRCBot(irc.bot.SingleServerIRCBot):
def on_welcome(self, c: ServerConnection, e: Event) -> None:
if len(self.nickserv_password) > 0:
msg = 'identify %s' % (self.nickserv_password,)
c.privmsg('NickServ', msg)
msg = "identify %s" % (self.nickserv_password,)
c.privmsg("NickServ", msg)
c.join(self.channel)
def forward_to_irc(msg: Dict[str, Any]) -> None:

View file

@ -17,8 +17,8 @@ from requests.exceptions import MissingSchema
import zulip
GENERAL_NETWORK_USERNAME_REGEX = '@_?[a-zA-Z0-9]+_([a-zA-Z0-9-_]+):[a-zA-Z0-9.]+'
MATRIX_USERNAME_REGEX = '@([a-zA-Z0-9-_]+):matrix.org'
GENERAL_NETWORK_USERNAME_REGEX = "@_?[a-zA-Z0-9]+_([a-zA-Z0-9-_]+):[a-zA-Z0-9.]+"
MATRIX_USERNAME_REGEX = "@([a-zA-Z0-9-_]+):matrix.org"
# change these templates to change the format of displayed message
ZULIP_MESSAGE_TEMPLATE = "**{username}**: {message}"
@ -77,10 +77,10 @@ def matrix_to_zulip(
"""
content = get_message_content_from_event(event, no_noise)
zulip_bot_user = '@%s:matrix.org' % (matrix_config['username'],)
zulip_bot_user = "@%s:matrix.org" % (matrix_config["username"],)
# We do this to identify the messages generated from Zulip -> Matrix
# and we make sure we don't forward it again to the Zulip stream.
not_from_zulip_bot = event['sender'] != zulip_bot_user
not_from_zulip_bot = event["sender"] != zulip_bot_user
if not_from_zulip_bot and content:
try:
@ -95,31 +95,31 @@ def matrix_to_zulip(
except Exception as exception: # XXX This should be more specific
# Generally raised when user is forbidden
raise Bridge_ZulipFatalException(exception)
if result['result'] != 'success':
if result["result"] != "success":
# Generally raised when API key is invalid
raise Bridge_ZulipFatalException(result['msg'])
raise Bridge_ZulipFatalException(result["msg"])
return _matrix_to_zulip
def get_message_content_from_event(event: Dict[str, Any], no_noise: bool) -> Optional[str]:
irc_nick = shorten_irc_nick(event['sender'])
if event['type'] == "m.room.member":
irc_nick = shorten_irc_nick(event["sender"])
if event["type"] == "m.room.member":
if no_noise:
return None
# Join and leave events can be noisy. They are ignored by default.
# To enable these events pass `no_noise` as `False` as the script argument
if event['membership'] == "join":
if event["membership"] == "join":
content = ZULIP_MESSAGE_TEMPLATE.format(username=irc_nick, message="joined")
elif event['membership'] == "leave":
elif event["membership"] == "leave":
content = ZULIP_MESSAGE_TEMPLATE.format(username=irc_nick, message="quit")
elif event['type'] == "m.room.message":
if event['content']['msgtype'] == "m.text" or event['content']['msgtype'] == "m.emote":
elif event["type"] == "m.room.message":
if event["content"]["msgtype"] == "m.text" or event["content"]["msgtype"] == "m.emote":
content = ZULIP_MESSAGE_TEMPLATE.format(
username=irc_nick, message=event['content']['body']
username=irc_nick, message=event["content"]["body"]
)
else:
content = event['type']
content = event["type"]
return content
@ -147,7 +147,7 @@ def zulip_to_matrix(config: Dict[str, Any], room: Any) -> Callable[[Dict[str, An
"""
message_valid = check_zulip_message_validity(msg, config)
if message_valid:
matrix_username = msg["sender_full_name"].replace(' ', '')
matrix_username = msg["sender_full_name"].replace(" ", "")
matrix_text = MATRIX_MESSAGE_TEMPLATE.format(
username=matrix_username, message=msg["content"]
)
@ -186,25 +186,25 @@ def generate_parser() -> argparse.ArgumentParser:
description=description, formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument(
'-c', '--config', required=False, help="Path to the config file for the bridge."
"-c", "--config", required=False, help="Path to the config file for the bridge."
)
parser.add_argument(
'--write-sample-config',
metavar='PATH',
dest='sample_config',
"--write-sample-config",
metavar="PATH",
dest="sample_config",
help="Generate a configuration template at the specified location.",
)
parser.add_argument(
'--from-zuliprc',
metavar='ZULIPRC',
dest='zuliprc',
"--from-zuliprc",
metavar="ZULIPRC",
dest="zuliprc",
help="Optional path to zuliprc file for bot, when using --write-sample-config",
)
parser.add_argument(
'--show-join-leave',
dest='no_noise',
"--show-join-leave",
dest="no_noise",
default=True,
action='store_false',
action="store_false",
help="Enable IRC join/leave events.",
)
return parser
@ -218,7 +218,7 @@ def read_configuration(config_file: str) -> Dict[str, Dict[str, str]]:
except configparser.Error as exception:
raise Bridge_ConfigException(str(exception))
if set(config.sections()) != {'matrix', 'zulip'}:
if set(config.sections()) != {"matrix", "zulip"}:
raise Bridge_ConfigException("Please ensure the configuration has zulip & matrix sections.")
# TODO Could add more checks for configuration content here
@ -235,25 +235,25 @@ def write_sample_config(target_path: str, zuliprc: Optional[str]) -> None:
sample_dict = OrderedDict(
(
(
'matrix',
"matrix",
OrderedDict(
(
('host', 'https://matrix.org'),
('username', 'username'),
('password', 'password'),
('room_id', '#zulip:matrix.org'),
("host", "https://matrix.org"),
("username", "username"),
("password", "password"),
("room_id", "#zulip:matrix.org"),
)
),
),
(
'zulip',
"zulip",
OrderedDict(
(
('email', 'glitch-bot@chat.zulip.org'),
('api_key', 'aPiKeY'),
('site', 'https://chat.zulip.org'),
('stream', 'test here'),
('topic', 'matrix'),
("email", "glitch-bot@chat.zulip.org"),
("api_key", "aPiKeY"),
("site", "https://chat.zulip.org"),
("stream", "test here"),
("topic", "matrix"),
)
),
),
@ -272,13 +272,13 @@ def write_sample_config(target_path: str, zuliprc: Optional[str]) -> None:
# Can add more checks for validity of zuliprc file here
sample_dict['zulip']['email'] = zuliprc_config['api']['email']
sample_dict['zulip']['site'] = zuliprc_config['api']['site']
sample_dict['zulip']['api_key'] = zuliprc_config['api']['key']
sample_dict["zulip"]["email"] = zuliprc_config["api"]["email"]
sample_dict["zulip"]["site"] = zuliprc_config["api"]["site"]
sample_dict["zulip"]["api_key"] = zuliprc_config["api"]["key"]
sample = configparser.ConfigParser()
sample.read_dict(sample_dict)
with open(target_path, 'w') as target:
with open(target_path, "w") as target:
sample.write(target)
@ -357,5 +357,5 @@ def main() -> None:
backoff.fail()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View file

@ -59,7 +59,7 @@ class MatrixBridgeScriptTests(TestCase):
usage = "usage: {} [-h]".format(script_file)
description = "Script to bridge"
self.assertIn(usage, output_lines[0])
blank_lines = [num for num, line in enumerate(output_lines) if line == '']
blank_lines = [num for num, line in enumerate(output_lines) if line == ""]
# There should be blank lines in the output
self.assertTrue(blank_lines)
# There should be finite output
@ -79,9 +79,9 @@ class MatrixBridgeScriptTests(TestCase):
def test_write_sample_config_from_zuliprc(self) -> None:
zuliprc_template = ["[api]", "email={email}", "key={key}", "site={site}"]
zulip_params = {
'email': 'foo@bar',
'key': 'some_api_key',
'site': 'https://some.chat.serverplace',
"email": "foo@bar",
"key": "some_api_key",
"site": "https://some.chat.serverplace",
}
with new_temp_dir() as tempdir:
path = os.path.join(tempdir, sample_config_path)
@ -103,9 +103,9 @@ class MatrixBridgeScriptTests(TestCase):
with open(path) as sample_file:
sample_lines = [line.strip() for line in sample_file.readlines()]
expected_lines = sample_config_text.split("\n")
expected_lines[7] = 'email = {}'.format(zulip_params['email'])
expected_lines[8] = 'api_key = {}'.format(zulip_params['key'])
expected_lines[9] = 'site = {}'.format(zulip_params['site'])
expected_lines[7] = "email = {}".format(zulip_params["email"])
expected_lines[8] = "api_key = {}".format(zulip_params["key"])
expected_lines[9] = "site = {}".format(zulip_params["site"])
self.assertEqual(sample_lines, expected_lines[:-1])
def test_detect_zuliprc_does_not_exist(self) -> None:
@ -131,31 +131,31 @@ class MatrixBridgeZulipToMatrixTests(TestCase):
valid_msg = dict(
sender_email="John@Smith.smith", # must not be equal to config:email
type="stream", # Can only mirror Zulip streams
display_recipient=valid_zulip_config['stream'],
subject=valid_zulip_config['topic'],
display_recipient=valid_zulip_config["stream"],
subject=valid_zulip_config["topic"],
)
def test_zulip_message_validity_success(self) -> None:
zulip_config = self.valid_zulip_config
msg = self.valid_msg
# Ensure the test inputs are valid for success
assert msg['sender_email'] != zulip_config['email']
assert msg["sender_email"] != zulip_config["email"]
self.assertTrue(check_zulip_message_validity(msg, zulip_config))
def test_zulip_message_validity_failure(self) -> None:
zulip_config = self.valid_zulip_config
msg_wrong_stream = dict(self.valid_msg, display_recipient='foo')
msg_wrong_stream = dict(self.valid_msg, display_recipient="foo")
self.assertFalse(check_zulip_message_validity(msg_wrong_stream, zulip_config))
msg_wrong_topic = dict(self.valid_msg, subject='foo')
msg_wrong_topic = dict(self.valid_msg, subject="foo")
self.assertFalse(check_zulip_message_validity(msg_wrong_topic, zulip_config))
msg_not_stream = dict(self.valid_msg, type="private")
self.assertFalse(check_zulip_message_validity(msg_not_stream, zulip_config))
msg_from_bot = dict(self.valid_msg, sender_email=zulip_config['email'])
msg_from_bot = dict(self.valid_msg, sender_email=zulip_config["email"])
self.assertFalse(check_zulip_message_validity(msg_from_bot, zulip_config))
def test_zulip_to_matrix(self) -> None:
@ -166,14 +166,14 @@ class MatrixBridgeZulipToMatrixTests(TestCase):
msg = dict(self.valid_msg, sender_full_name="John Smith")
expected = {
'hi': '{} hi',
'*hi*': '{} *hi*',
'**hi**': '{} **hi**',
"hi": "{} hi",
"*hi*": "{} *hi*",
"**hi**": "{} **hi**",
}
for content in expected:
send_msg(dict(msg, content=content))
for (method, params, _), expect in zip(room.method_calls, expected.values()):
self.assertEqual(method, 'send_text')
self.assertEqual(params[0], expect.format('<JohnSmith>'))
self.assertEqual(method, "send_text")
self.assertEqual(params[0], expect.format("<JohnSmith>"))

View file

@ -55,17 +55,17 @@ class SlackBridge:
self.slack_webclient = slack_sdk.WebClient(token=self.slack_config["token"])
def wrap_slack_mention_with_bracket(self, zulip_msg: Dict[str, Any]) -> None:
words = zulip_msg["content"].split(' ')
words = zulip_msg["content"].split(" ")
for w in words:
if w.startswith('@'):
zulip_msg["content"] = zulip_msg["content"].replace(w, '<' + w + '>')
if w.startswith("@"):
zulip_msg["content"] = zulip_msg["content"].replace(w, "<" + w + ">")
def replace_slack_id_with_name(self, msg: Dict[str, Any]) -> None:
words = msg['text'].split(' ')
words = msg["text"].split(" ")
for w in words:
if w.startswith('<@') and w.endswith('>'):
if w.startswith("<@") and w.endswith(">"):
_id = w[2:-1]
msg['text'] = msg['text'].replace(_id, self.slack_id_to_name[_id])
msg["text"] = msg["text"].replace(_id, self.slack_id_to_name[_id])
def zulip_to_slack(self) -> Callable[[Dict[str, Any]], None]:
def _zulip_to_slack(msg: Dict[str, Any]) -> None:
@ -83,25 +83,25 @@ class SlackBridge:
return _zulip_to_slack
def run_slack_listener(self) -> None:
members = self.slack_webclient.users_list()['members']
members = self.slack_webclient.users_list()["members"]
# See also https://api.slack.com/changelog/2017-09-the-one-about-usernames
self.slack_id_to_name = {
u["id"]: u["profile"].get("display_name", u["profile"]["real_name"]) for u in members
}
self.slack_name_to_id = {v: k for k, v in self.slack_id_to_name.items()}
@RTMClient.run_on(event='message')
@RTMClient.run_on(event="message")
def slack_to_zulip(**payload: Any) -> None:
msg = payload['data']
if msg['channel'] != self.channel:
msg = payload["data"]
if msg["channel"] != self.channel:
return
user_id = msg['user']
user_id = msg["user"]
user = self.slack_id_to_name[user_id]
from_bot = user == self.slack_config['username']
from_bot = user == self.slack_config["username"]
if from_bot:
return
self.replace_slack_id_with_name(msg)
content = ZULIP_MESSAGE_TEMPLATE.format(username=user, message=msg['text'])
content = ZULIP_MESSAGE_TEMPLATE.format(username=user, message=msg["text"])
msg_data = dict(
type="stream", to=self.zulip_stream, subject=self.zulip_subject, content=content
)
@ -117,7 +117,7 @@ if __name__ == "__main__":
the first realm to a channel in a Slack workspace.
"""
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
parser = argparse.ArgumentParser(usage=usage)
print("Starting slack mirroring bot")

View file

@ -44,7 +44,7 @@ client = zulip.Client(
user_agent = "Codebase To Zulip Mirroring script (zulip-devel@googlegroups.com)"
# find some form of JSON loader/dumper, with a preference order for speed.
json_implementations = ['ujson', 'cjson', 'simplejson', 'json']
json_implementations = ["ujson", "cjson", "simplejson", "json"]
while len(json_implementations):
try:
@ -58,7 +58,7 @@ def make_api_call(path: str) -> Optional[List[Dict[str, Any]]]:
response = requests.get(
"https://api3.codebasehq.com/%s" % (path,),
auth=(config.CODEBASE_API_USERNAME, config.CODEBASE_API_KEY),
params={'raw': 'True'},
params={"raw": "True"},
headers={
"User-Agent": user_agent,
"Content-Type": "application/json",
@ -86,36 +86,36 @@ def make_url(path: str) -> str:
def handle_event(event: Dict[str, Any]) -> None:
event = event['event']
event_type = event['type']
actor_name = event['actor_name']
event = event["event"]
event_type = event["type"]
actor_name = event["actor_name"]
raw_props = event.get('raw_properties', {})
raw_props = event.get("raw_properties", {})
project_link = raw_props.get('project_permalink')
project_link = raw_props.get("project_permalink")
subject = None
content = None
if event_type == 'repository_creation':
if event_type == "repository_creation":
stream = config.ZULIP_COMMITS_STREAM_NAME
project_name = raw_props.get('name')
project_repo_type = raw_props.get('scm_type')
project_name = raw_props.get("name")
project_repo_type = raw_props.get("scm_type")
url = make_url("projects/%s" % (project_link,))
scm = "of type %s" % (project_repo_type,) if project_repo_type else ""
subject = "Repository %s Created" % (project_name,)
content = "%s created a new repository %s [%s](%s)" % (actor_name, scm, project_name, url)
elif event_type == 'push':
elif event_type == "push":
stream = config.ZULIP_COMMITS_STREAM_NAME
num_commits = raw_props.get('commits_count')
branch = raw_props.get('ref_name')
project = raw_props.get('project_name')
repo_link = raw_props.get('repository_permalink')
deleted_ref = raw_props.get('deleted_ref')
new_ref = raw_props.get('new_ref')
num_commits = raw_props.get("commits_count")
branch = raw_props.get("ref_name")
project = raw_props.get("project_name")
repo_link = raw_props.get("repository_permalink")
deleted_ref = raw_props.get("deleted_ref")
new_ref = raw_props.get("new_ref")
subject = "Push to %s on %s" % (branch, project)
@ -130,20 +130,20 @@ def handle_event(event: Dict[str, Any]) -> None:
branch,
project,
)
for commit in raw_props.get('commits'):
ref = commit.get('ref')
for commit in raw_props.get("commits"):
ref = commit.get("ref")
url = make_url(
"projects/%s/repositories/%s/commit/%s" % (project_link, repo_link, ref)
)
message = commit.get('message')
message = commit.get("message")
content += "* [%s](%s): %s\n" % (ref, url, message)
elif event_type == 'ticketing_ticket':
elif event_type == "ticketing_ticket":
stream = config.ZULIP_TICKETS_STREAM_NAME
num = raw_props.get('number')
name = raw_props.get('subject')
assignee = raw_props.get('assignee')
priority = raw_props.get('priority')
num = raw_props.get("number")
name = raw_props.get("subject")
assignee = raw_props.get("assignee")
priority = raw_props.get("priority")
url = make_url("projects/%s/tickets/%s" % (project_link, num))
if assignee is None:
@ -153,13 +153,13 @@ def handle_event(event: Dict[str, Any]) -> None:
"""%s created a new ticket [#%s](%s) priority **%s** assigned to %s:\n\n~~~ quote\n %s"""
% (actor_name, num, url, priority, assignee, name)
)
elif event_type == 'ticketing_note':
elif event_type == "ticketing_note":
stream = config.ZULIP_TICKETS_STREAM_NAME
num = raw_props.get('number')
name = raw_props.get('subject')
body = raw_props.get('content')
changes = raw_props.get('changes')
num = raw_props.get("number")
name = raw_props.get("subject")
body = raw_props.get("content")
changes = raw_props.get("changes")
url = make_url("projects/%s/tickets/%s" % (project_link, num))
subject = "#%s: %s" % (num, name)
@ -173,33 +173,33 @@ def handle_event(event: Dict[str, Any]) -> None:
body,
)
if 'status_id' in changes:
status_change = changes.get('status_id')
if "status_id" in changes:
status_change = changes.get("status_id")
content += "Status changed from **%s** to **%s**\n\n" % (
status_change[0],
status_change[1],
)
elif event_type == 'ticketing_milestone':
elif event_type == "ticketing_milestone":
stream = config.ZULIP_TICKETS_STREAM_NAME
name = raw_props.get('name')
identifier = raw_props.get('identifier')
name = raw_props.get("name")
identifier = raw_props.get("identifier")
url = make_url("projects/%s/milestone/%s" % (project_link, identifier))
subject = name
content = "%s created a new milestone [%s](%s)" % (actor_name, name, url)
elif event_type == 'comment':
elif event_type == "comment":
stream = config.ZULIP_COMMITS_STREAM_NAME
comment = raw_props.get('content')
commit = raw_props.get('commit_ref')
comment = raw_props.get("content")
commit = raw_props.get("commit_ref")
# If there's a commit id, it's a comment to a commit
if commit:
repo_link = raw_props.get('repository_permalink')
repo_link = raw_props.get("repository_permalink")
url = make_url(
'projects/%s/repositories/%s/commit/%s' % (project_link, repo_link, commit)
"projects/%s/repositories/%s/commit/%s" % (project_link, repo_link, commit)
)
subject = "%s commented on %s" % (actor_name, commit)
@ -223,14 +223,14 @@ def handle_event(event: Dict[str, Any]) -> None:
else:
content = "%s posted:\n\n~~~ quote\n%s\n~~~" % (actor_name, comment_content)
elif event_type == 'deployment':
elif event_type == "deployment":
stream = config.ZULIP_COMMITS_STREAM_NAME
start_ref = raw_props.get('start_ref')
end_ref = raw_props.get('end_ref')
environment = raw_props.get('environment')
servers = raw_props.get('servers')
repo_link = raw_props.get('repository_permalink')
start_ref = raw_props.get("start_ref")
end_ref = raw_props.get("end_ref")
environment = raw_props.get("environment")
servers = raw_props.get("servers")
repo_link = raw_props.get("repository_permalink")
start_ref_url = make_url(
"projects/%s/repositories/%s/commit/%s" % (project_link, repo_link, start_ref)
@ -259,30 +259,30 @@ def handle_event(event: Dict[str, Any]) -> None:
", ".join(["`%s`" % (server,) for server in servers])
)
elif event_type == 'named_tree':
elif event_type == "named_tree":
# Docs say named_tree type used for new/deleting branches and tags,
# but experimental testing showed that they were all sent as 'push' events
pass
elif event_type == 'wiki_page':
elif event_type == "wiki_page":
logging.warn("Wiki page notifications not yet implemented")
elif event_type == 'sprint_creation':
elif event_type == "sprint_creation":
logging.warn("Sprint notifications not yet implemented")
elif event_type == 'sprint_ended':
elif event_type == "sprint_ended":
logging.warn("Sprint notifications not yet implemented")
else:
logging.info("Unknown event type %s, ignoring!" % (event_type,))
if subject and content:
if len(subject) > 60:
subject = subject[:57].rstrip() + '...'
subject = subject[:57].rstrip() + "..."
res = client.send_message(
{"type": "stream", "to": stream, "subject": subject, "content": content}
)
if res['result'] == 'success':
logging.info("Successfully sent Zulip with id: %s" % (res['id'],))
if res["result"] == "success":
logging.info("Successfully sent Zulip with id: %s" % (res["id"],))
else:
logging.warn("Failed to send Zulip: %s %s" % (res['result'], res['msg']))
logging.warn("Failed to send Zulip: %s %s" % (res["result"], res["msg"]))
# the main run loop for this mirror script
@ -295,7 +295,7 @@ def run_mirror() -> None:
try:
with open(config.RESUME_FILE) as f:
timestamp = f.read()
if timestamp == '':
if timestamp == "":
since = default_since()
else:
since = datetime.fromtimestamp(float(timestamp), tz=pytz.utc)
@ -310,7 +310,7 @@ def run_mirror() -> None:
if events is not None:
sleepInterval = 1
for event in events[::-1]:
timestamp = event.get('event', {}).get('timestamp', '')
timestamp = event.get("event", {}).get("timestamp", "")
event_date = dateutil.parser.parse(timestamp)
if event_date > since:
handle_event(event)
@ -322,7 +322,7 @@ def run_mirror() -> None:
time.sleep(sleepInterval)
except KeyboardInterrupt:
open(config.RESUME_FILE, 'w').write(since.strftime("%s"))
open(config.RESUME_FILE, "w").write(since.strftime("%s"))
logging.info("Shutting down Codebase mirror")

View file

@ -43,19 +43,19 @@ def git_repository_name() -> Text:
def git_commit_range(oldrev: str, newrev: str) -> str:
log_cmd = ["git", "log", "--reverse", "--pretty=%aE %H %s", "%s..%s" % (oldrev, newrev)]
commits = ''
commits = ""
for ln in subprocess.check_output(log_cmd, universal_newlines=True).splitlines():
author_email, commit_id, subject = ln.split(None, 2)
if hasattr(config, "format_commit_message"):
commits += config.format_commit_message(author_email, subject, commit_id)
else:
commits += '!avatar(%s) %s\n' % (author_email, subject)
commits += "!avatar(%s) %s\n" % (author_email, subject)
return commits
def send_bot_message(oldrev: str, newrev: str, refname: str) -> None:
repo_name = git_repository_name()
branch = refname.replace('refs/heads/', '')
branch = refname.replace("refs/heads/", "")
destination = config.commit_notice_destination(repo_name, branch, newrev)
if destination is None:
# Don't forward the notice anywhere
@ -65,30 +65,30 @@ def send_bot_message(oldrev: str, newrev: str, refname: str) -> None:
old_head = oldrev[:12]
if (
oldrev == '0000000000000000000000000000000000000000'
or newrev == '0000000000000000000000000000000000000000'
oldrev == "0000000000000000000000000000000000000000"
or newrev == "0000000000000000000000000000000000000000"
):
# New branch pushed or old branch removed
added = ''
removed = ''
added = ""
removed = ""
else:
added = git_commit_range(oldrev, newrev)
removed = git_commit_range(newrev, oldrev)
if oldrev == '0000000000000000000000000000000000000000':
message = '`%s` was pushed to new branch `%s`' % (new_head, branch)
elif newrev == '0000000000000000000000000000000000000000':
message = 'branch `%s` was removed (was `%s`)' % (branch, old_head)
if oldrev == "0000000000000000000000000000000000000000":
message = "`%s` was pushed to new branch `%s`" % (new_head, branch)
elif newrev == "0000000000000000000000000000000000000000":
message = "branch `%s` was removed (was `%s`)" % (branch, old_head)
elif removed:
message = '`%s` was pushed to `%s`, **REMOVING**:\n\n%s' % (new_head, branch, removed)
message = "`%s` was pushed to `%s`, **REMOVING**:\n\n%s" % (new_head, branch, removed)
if added:
message += '\n**and adding**:\n\n' + added
message += '\n**A HISTORY REWRITE HAS OCCURRED!**'
message += '\n@everyone: Please check your local branches to deal with this.'
message += "\n**and adding**:\n\n" + added
message += "\n**A HISTORY REWRITE HAS OCCURRED!**"
message += "\n@everyone: Please check your local branches to deal with this."
elif added:
message = '`%s` was deployed to `%s` with:\n\n%s' % (new_head, branch, added)
message = "`%s` was deployed to `%s` with:\n\n%s" % (new_head, branch, added)
else:
message = '`%s` was pushed to `%s`... but nothing changed?' % (new_head, branch)
message = "`%s` was pushed to `%s`... but nothing changed?" % (new_head, branch)
message_data = {
"type": "stream",

View file

@ -2,7 +2,7 @@
from typing import Dict, Optional, Text
# Name of the stream to send notifications to, default is "commits"
STREAM_NAME = 'commits'
STREAM_NAME = "commits"
# Change these values to configure authentication for the plugin
ZULIP_USER = "git-bot@example.com"
@ -37,7 +37,7 @@ def commit_notice_destination(repo: Text, branch: Text, commit: Text) -> Optiona
#
# return '!avatar(%s) [%s](https://example.com/commits/%s)\n' % (author, subject, commit_id)
def format_commit_message(author: Text, subject: Text, commit_id: Text) -> Text:
return '!avatar(%s) %s\n' % (author, subject)
return "!avatar(%s) %s\n" % (author, subject)
## If properly installed, the Zulip API should be in your import

View file

@ -18,12 +18,12 @@ except ImportError:
# at zulip/bots/gcal/
# NOTE: When adding more scopes, add them after the previous one in the same field, with a space
# seperating them.
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
SCOPES = "https://www.googleapis.com/auth/calendar.readonly"
# This file contains the information that google uses to figure out which application is requesting
# this client's data.
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Zulip Calendar Bot'
HOME_DIR = os.path.expanduser('~')
CLIENT_SECRET_FILE = "client_secret.json"
APPLICATION_NAME = "Zulip Calendar Bot"
HOME_DIR = os.path.expanduser("~")
def get_credentials() -> client.Credentials:
@ -36,7 +36,7 @@ def get_credentials() -> client.Credentials:
Credentials, the obtained credential.
"""
credential_path = os.path.join(HOME_DIR, 'google-credentials.json')
credential_path = os.path.join(HOME_DIR, "google-credentials.json")
store = Storage(credential_path)
credentials = store.get()
@ -50,7 +50,7 @@ def get_credentials() -> client.Credentials:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
print("Storing credentials to " + credential_path)
get_credentials()

View file

@ -20,15 +20,15 @@ from oauth2client.file import Storage
try:
from googleapiclient import discovery
except ImportError:
logging.exception('Install google-api-python-client')
logging.exception("Install google-api-python-client")
sys.path.append(os.path.join(os.path.dirname(__file__), '../../'))
sys.path.append(os.path.join(os.path.dirname(__file__), "../../"))
import zulip
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Zulip'
HOME_DIR = os.path.expanduser('~')
SCOPES = "https://www.googleapis.com/auth/calendar.readonly"
CLIENT_SECRET_FILE = "client_secret.json"
APPLICATION_NAME = "Zulip"
HOME_DIR = os.path.expanduser("~")
# Our cached view of the calendar, updated periodically.
events = [] # type: List[Tuple[int, datetime.datetime, str]]
@ -61,28 +61,28 @@ google-calendar --calendar calendarID@example.calendar.google.com
parser.add_argument(
'--interval',
dest='interval',
"--interval",
dest="interval",
default=30,
type=int,
action='store',
help='Minutes before event for reminder [default: 30]',
metavar='MINUTES',
action="store",
help="Minutes before event for reminder [default: 30]",
metavar="MINUTES",
)
parser.add_argument(
'--calendar',
dest='calendarID',
default='primary',
"--calendar",
dest="calendarID",
default="primary",
type=str,
action='store',
help='Calendar ID for the calendar you want to receive reminders from.',
action="store",
help="Calendar ID for the calendar you want to receive reminders from.",
)
options = parser.parse_args()
if not (options.zulip_email):
parser.error('You must specify --user')
parser.error("You must specify --user")
zulip_client = zulip.init_from_options(options)
@ -98,14 +98,14 @@ def get_credentials() -> client.Credentials:
Credentials, the obtained credential.
"""
try:
credential_path = os.path.join(HOME_DIR, 'google-credentials.json')
credential_path = os.path.join(HOME_DIR, "google-credentials.json")
store = Storage(credential_path)
credentials = store.get()
return credentials
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 OSError:
logging.error("Run the get-google-credentials script from this directory first.")
@ -115,7 +115,7 @@ def populate_events() -> Optional[None]:
credentials = get_credentials()
creds = credentials.authorize(httplib2.Http())
service = discovery.build('calendar', 'v3', http=creds)
service = discovery.build("calendar", "v3", http=creds)
now = datetime.datetime.now(pytz.utc).isoformat()
feed = (
@ -125,7 +125,7 @@ def populate_events() -> Optional[None]:
timeMin=now,
maxResults=5,
singleEvents=True,
orderBy='startTime',
orderBy="startTime",
)
.execute()
)
@ -174,10 +174,10 @@ def send_reminders() -> Optional[None]:
key = (id, start)
if key not in sent:
if start.hour == 0 and start.minute == 0:
line = '%s is today.' % (summary,)
line = "%s is today." % (summary,)
else:
line = '%s starts at %s' % (summary, start.strftime('%H:%M'))
print('Sending reminder:', line)
line = "%s starts at %s" % (summary, start.strftime("%H:%M"))
print("Sending reminder:", line)
messages.append(line)
keys.add(key)
@ -185,12 +185,12 @@ def send_reminders() -> Optional[None]:
return
if len(messages) == 1:
message = 'Reminder: ' + messages[0]
message = "Reminder: " + messages[0]
else:
message = 'Reminder:\n\n' + '\n'.join('* ' + m for m in messages)
message = "Reminder:\n\n" + "\n".join("* " + m for m in messages)
zulip_client.send_message(
dict(type='private', to=options.zulip_email, sender=options.zulip_email, content=message)
dict(type="private", to=options.zulip_email, sender=options.zulip_email, content=message)
)
sent.update(keys)

View file

@ -94,7 +94,7 @@ def send_zulip(
def get_config(ui: ui, item: str) -> str:
try:
# config returns configuration value.
return ui.config('zulip', item)
return ui.config("zulip", item)
except IndexError:
ui.warn("Zulip: Could not find required item {} in hg config.".format(item))
sys.exit(1)

View file

@ -62,7 +62,7 @@ def stream_to_room(stream: str) -> str:
def jid_to_zulip(jid: JID) -> str:
suffix = ''
suffix = ""
if not jid.username.endswith("-bot"):
suffix = options.zulip_email_suffix
return "%s%s@%s" % (jid.username, suffix, options.zulip_domain)
@ -94,10 +94,10 @@ class JabberToZulipBot(ClientXMPP):
self.zulip = None
self.use_ipv6 = False
self.register_plugin('xep_0045') # Jabber chatrooms
self.register_plugin('xep_0199') # XMPP Ping
self.register_plugin("xep_0045") # Jabber chatrooms
self.register_plugin("xep_0199") # XMPP Ping
def set_zulip_client(self, zulipToJabberClient: 'ZulipToJabberBot') -> None:
def set_zulip_client(self, zulipToJabberClient: "ZulipToJabberBot") -> None:
self.zulipToJabber = zulipToJabberClient
def session_start(self, event: Dict[str, Any]) -> None:
@ -112,7 +112,7 @@ class JabberToZulipBot(ClientXMPP):
logging.debug("Joining " + room)
self.rooms.add(room)
muc_jid = JID(local=room, domain=options.conference_domain)
xep0045 = self.plugin['xep_0045']
xep0045 = self.plugin["xep_0045"]
try:
xep0045.joinMUC(muc_jid, self.nick, wait=True)
except InvalidJID:
@ -137,7 +137,7 @@ class JabberToZulipBot(ClientXMPP):
logging.debug("Leaving " + room)
self.rooms.remove(room)
muc_jid = JID(local=room, domain=options.conference_domain)
self.plugin['xep_0045'].leaveMUC(muc_jid, self.nick)
self.plugin["xep_0045"].leaveMUC(muc_jid, self.nick)
def message(self, msg: JabberMessage) -> Any:
try:
@ -152,7 +152,7 @@ class JabberToZulipBot(ClientXMPP):
logging.exception("Error forwarding Jabber => Zulip")
def private(self, msg: JabberMessage) -> None:
if options.mode == 'public' or msg['thread'] == '\u1FFFE':
if options.mode == "public" or msg["thread"] == "\u1FFFE":
return
sender = jid_to_zulip(msg["from"])
recipient = jid_to_zulip(msg["to"])
@ -168,13 +168,13 @@ class JabberToZulipBot(ClientXMPP):
logging.error(str(ret))
def group(self, msg: JabberMessage) -> None:
if options.mode == 'personal' or msg["thread"] == '\u1FFFE':
if options.mode == "personal" or msg["thread"] == "\u1FFFE":
return
subject = msg["subject"]
if len(subject) == 0:
subject = "(no topic)"
stream = room_to_stream(msg['from'].local)
stream = room_to_stream(msg["from"].local)
sender_nick = msg.get_mucnick()
if not sender_nick:
# Messages from the room itself have no nickname. We should not try
@ -195,9 +195,9 @@ class JabberToZulipBot(ClientXMPP):
logging.error(str(ret))
def nickname_to_jid(self, room: str, nick: str) -> JID:
jid = self.plugin['xep_0045'].getJidProperty(room, nick, "jid")
if jid is None or jid == '':
return JID(local=nick.replace(' ', ''), domain=self.boundjid.domain)
jid = self.plugin["xep_0045"].getJidProperty(room, nick, "jid")
if jid is None or jid == "":
return JID(local=nick.replace(" ", ""), domain=self.boundjid.domain)
else:
return jid
@ -211,59 +211,59 @@ class ZulipToJabberBot:
self.jabber = client
def process_event(self, event: Dict[str, Any]) -> None:
if event['type'] == 'message':
if event["type"] == "message":
message = event["message"]
if message['sender_email'] != self.client.email:
if message["sender_email"] != self.client.email:
return
try:
if message['type'] == 'stream':
if message["type"] == "stream":
self.stream_message(message)
elif message['type'] == 'private':
elif message["type"] == "private":
self.private_message(message)
except Exception:
logging.exception("Exception forwarding Zulip => Jabber")
elif event['type'] == 'subscription':
elif event["type"] == "subscription":
self.process_subscription(event)
def stream_message(self, msg: Dict[str, str]) -> None:
assert self.jabber is not None
stream = msg['display_recipient']
stream = msg["display_recipient"]
if not stream.endswith("/xmpp"):
return
room = stream_to_room(stream)
jabber_recipient = JID(local=room, domain=options.conference_domain)
outgoing = self.jabber.make_message(
mto=jabber_recipient, mbody=msg['content'], mtype='groupchat'
mto=jabber_recipient, mbody=msg["content"], mtype="groupchat"
)
outgoing['thread'] = '\u1FFFE'
outgoing["thread"] = "\u1FFFE"
outgoing.send()
def private_message(self, msg: Dict[str, Any]) -> None:
assert self.jabber is not None
for recipient in msg['display_recipient']:
for recipient in msg["display_recipient"]:
if recipient["email"] == self.client.email:
continue
if not recipient["is_mirror_dummy"]:
continue
recip_email = recipient['email']
recip_email = recipient["email"]
jabber_recipient = zulip_to_jid(recip_email, self.jabber.boundjid.domain)
outgoing = self.jabber.make_message(
mto=jabber_recipient, mbody=msg['content'], mtype='chat'
mto=jabber_recipient, mbody=msg["content"], mtype="chat"
)
outgoing['thread'] = '\u1FFFE'
outgoing["thread"] = "\u1FFFE"
outgoing.send()
def process_subscription(self, event: Dict[str, Any]) -> None:
assert self.jabber is not None
if event['op'] == 'add':
streams = [s['name'].lower() for s in event['subscriptions']]
if event["op"] == "add":
streams = [s["name"].lower() for s in event["subscriptions"]]
streams = [s for s in streams if s.endswith("/xmpp")]
for stream in streams:
self.jabber.join_muc(stream_to_room(stream))
if event['op'] == 'remove':
streams = [s['name'].lower() for s in event['subscriptions']]
if event["op"] == "remove":
streams = [s["name"].lower() for s in event["subscriptions"]]
streams = [s for s in streams if s.endswith("/xmpp")]
for stream in streams:
self.jabber.leave_muc(stream_to_room(stream))
@ -277,14 +277,14 @@ def get_rooms(zulipToJabber: ZulipToJabberBot) -> List[str]:
sys.exit("Could not get initial list of Zulip %s" % (key,))
return ret[key]
if options.mode == 'public':
if options.mode == "public":
stream_infos = get_stream_infos("streams", zulipToJabber.client.get_streams)
else:
stream_infos = get_stream_infos("subscriptions", zulipToJabber.client.get_subscriptions)
rooms = [] # type: List[str]
for stream_info in stream_infos:
stream = stream_info['name']
stream = stream_info["name"]
if stream.endswith("/xmpp"):
rooms.append(stream_to_room(stream))
return rooms
@ -295,20 +295,20 @@ def config_error(msg: str) -> None:
sys.exit(2)
if __name__ == '__main__':
if __name__ == "__main__":
parser = optparse.OptionParser(
epilog='''Most general and Jabber configuration options may also be specified in the
epilog="""Most general and Jabber configuration options may also be specified in the
zulip configuration file under the jabber_mirror section (exceptions are noted
in their help sections). Keys have the same name as options with hyphens
replaced with underscores. Zulip configuration options go in the api section,
as normal.'''.replace(
as normal.""".replace(
"\n", " "
)
)
parser.add_option(
'--mode',
"--mode",
default=None,
action='store',
action="store",
help='''Which mode to run in. Valid options are "personal" and "public". In
"personal" mode, the mirror uses an individual users' credentials and mirrors
all messages they send on Zulip to Jabber and all private Jabber messages to
@ -319,33 +319,33 @@ user and mirrors messages sent to Jabber rooms to Zulip. Defaults to
),
)
parser.add_option(
'--zulip-email-suffix',
"--zulip-email-suffix",
default=None,
action='store',
help='''Add the specified suffix to the local part of email addresses constructed
action="store",
help="""Add the specified suffix to the local part of email addresses constructed
from JIDs and nicks before sending requests to the Zulip server, and remove the
suffix before sending requests to the Jabber server. For example, specifying
"+foo" will cause messages that are sent to the "bar" room by nickname "qux" to
be mirrored to the "bar/xmpp" stream in Zulip by user "qux+foo@example.com". This
option does not affect login credentials.'''.replace(
option does not affect login credentials.""".replace(
"\n", " "
),
)
parser.add_option(
'-d',
'--debug',
help='set logging to DEBUG. Can not be set via config file.',
action='store_const',
dest='log_level',
"-d",
"--debug",
help="set logging to DEBUG. Can not be set via config file.",
action="store_const",
dest="log_level",
const=logging.DEBUG,
default=logging.INFO,
)
jabber_group = optparse.OptionGroup(parser, "Jabber configuration")
jabber_group.add_option(
'--jid',
"--jid",
default=None,
action='store',
action="store",
help="Your Jabber JID. If a resource is specified, "
"it will be used as the nickname when joining MUCs. "
"Specifying the nickname is mostly useful if you want "
@ -353,27 +353,27 @@ option does not affect login credentials.'''.replace(
"from a dedicated account.",
)
jabber_group.add_option(
'--jabber-password', default=None, action='store', help="Your Jabber password"
"--jabber-password", default=None, action="store", help="Your Jabber password"
)
jabber_group.add_option(
'--conference-domain',
"--conference-domain",
default=None,
action='store',
action="store",
help="Your Jabber conference domain (E.g. conference.jabber.example.com). "
"If not specifed, \"conference.\" will be prepended to your JID's domain.",
'If not specifed, "conference." will be prepended to your JID\'s domain.',
)
jabber_group.add_option('--no-use-tls', default=None, action='store_true')
jabber_group.add_option("--no-use-tls", default=None, action="store_true")
jabber_group.add_option(
'--jabber-server-address',
"--jabber-server-address",
default=None,
action='store',
action="store",
help="The hostname of your Jabber server. This is only needed if "
"your server is missing SRV records",
)
jabber_group.add_option(
'--jabber-server-port',
default='5222',
action='store',
"--jabber-server-port",
default="5222",
action="store",
help="The port of your Jabber server. This is only needed if "
"your server is missing SRV records",
)
@ -382,7 +382,7 @@ option does not affect login credentials.'''.replace(
parser.add_option_group(zulip.generate_option_group(parser, "zulip-"))
(options, args) = parser.parse_args()
logging.basicConfig(level=options.log_level, format='%(levelname)-8s %(message)s')
logging.basicConfig(level=options.log_level, format="%(levelname)-8s %(message)s")
if options.zulip_config_file is None:
default_config_file = zulip.get_default_config_filename()
@ -422,9 +422,9 @@ option does not affect login credentials.'''.replace(
options.mode = "personal"
if options.zulip_email_suffix is None:
options.zulip_email_suffix = ''
options.zulip_email_suffix = ""
if options.mode not in ('public', 'personal'):
if options.mode not in ("public", "personal"):
config_error("Bad value for --mode: must be one of 'public' or 'personal'")
if None in (options.jid, options.jabber_password):
@ -437,7 +437,7 @@ option does not affect login credentials.'''.replace(
zulip.init_from_options(options, "JabberMirror/" + __version__)
)
# This won't work for open realms that don't have a consistent domain
options.zulip_domain = zulipToJabber.client.email.partition('@')[-1]
options.zulip_domain = zulipToJabber.client.email.partition("@")[-1]
try:
jid = JID(options.jid)
@ -460,10 +460,10 @@ option does not affect login credentials.'''.replace(
zulipToJabber.set_jabber_client(xmpp)
xmpp.process(block=False)
if options.mode == 'public':
event_types = ['stream']
if options.mode == "public":
event_types = ["stream"]
else:
event_types = ['message', 'subscription']
event_types = ["message", "subscription"]
try:
logging.info("Connecting to Zulip.")

View file

@ -96,7 +96,7 @@ def process_logs() -> None:
# immediately after rotation, this tool won't notice.
file_data["last"] = 1
output = subprocess.check_output(["tail", "-n+%s" % (file_data["last"],), log_file])
new_lines = output.decode('utf-8', errors='replace').split('\n')[:-1]
new_lines = output.decode("utf-8", errors="replace").split("\n")[:-1]
if len(new_lines) > 0:
process_lines(new_lines, log_file)
file_data["last"] += len(new_lines)

View file

@ -9,19 +9,19 @@ VERSION = "0.9"
# In Nagios, "output" means "first line of output", and "long
# output" means "other lines of output".
parser = zulip.add_default_arguments(argparse.ArgumentParser()) # type: argparse.ArgumentParser
parser.add_argument('--output', default='')
parser.add_argument('--long-output', default='')
parser.add_argument('--stream', default='nagios')
parser.add_argument('--config', default='/etc/nagios3/zuliprc')
for opt in ('type', 'host', 'service', 'state'):
parser.add_argument('--' + opt)
parser.add_argument("--output", default="")
parser.add_argument("--long-output", default="")
parser.add_argument("--stream", default="nagios")
parser.add_argument("--config", default="/etc/nagios3/zuliprc")
for opt in ("type", "host", "service", "state"):
parser.add_argument("--" + opt)
opts = parser.parse_args()
client = zulip.Client(
config_file=opts.config, client="ZulipNagios/" + VERSION
) # type: zulip.Client
msg = dict(type='stream', to=opts.stream) # type: Dict[str, Any]
msg = dict(type="stream", to=opts.stream) # type: Dict[str, Any]
# Set a subject based on the host or service in question. This enables
# threaded discussion of multiple concurrent issues, and provides useful
@ -30,24 +30,24 @@ msg = dict(type='stream', to=opts.stream) # type: Dict[str, Any]
# We send PROBLEM and RECOVERY messages to the same subject.
if opts.service is None:
# Host notification
thing = 'host' # type: Text
msg['subject'] = 'host %s' % (opts.host,)
thing = "host" # type: Text
msg["subject"] = "host %s" % (opts.host,)
else:
# Service notification
thing = 'service'
msg['subject'] = 'service %s on %s' % (opts.service, opts.host)
thing = "service"
msg["subject"] = "service %s on %s" % (opts.service, opts.host)
if len(msg['subject']) > 60:
msg['subject'] = msg['subject'][0:57].rstrip() + "..."
if len(msg["subject"]) > 60:
msg["subject"] = msg["subject"][0:57].rstrip() + "..."
# e.g. **PROBLEM**: service is CRITICAL
msg['content'] = '**%s**: %s is %s' % (opts.type, thing, opts.state)
msg["content"] = "**%s**: %s is %s" % (opts.type, thing, opts.state)
# The "long output" can contain newlines represented by "\n" escape sequences.
# The Nagios mail command uses /usr/bin/printf "%b" to expand these.
# We will be more conservative and handle just this one escape sequence.
output = (opts.output + '\n' + opts.long_output.replace(r'\n', '\n')).strip() # type: Text
output = (opts.output + "\n" + opts.long_output.replace(r"\n", "\n")).strip() # type: Text
if output:
# Put any command output in a code block.
msg['content'] += '\n\n~~~~\n' + output + "\n~~~~\n"
msg["content"] += "\n\n~~~~\n" + output + "\n~~~~\n"
client.send_message(msg)

View file

@ -10,7 +10,7 @@ from typing import Dict
sys.path.insert(0, os.path.dirname(__file__))
import zulip_openshift_config as config
VERSION = '0.1'
VERSION = "0.1"
if config.ZULIP_API_PATH is not None:
sys.path.append(config.ZULIP_API_PATH)
@ -21,7 +21,7 @@ client = zulip.Client(
email=config.ZULIP_USER,
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client='ZulipOpenShift/' + VERSION,
client="ZulipOpenShift/" + VERSION,
)
@ -29,19 +29,19 @@ def get_deployment_details() -> Dict[str, str]:
# "gear deployments" output example:
# Activation time - Deployment ID - Git Ref - Git SHA1
# 2017-01-07 15:40:30 -0500 - 9e2b7143 - master - b9ce57c - ACTIVE
dep = subprocess.check_output(['gear', 'deployments'], universal_newlines=True).splitlines()[1]
splits = dep.split(' - ')
dep = subprocess.check_output(["gear", "deployments"], universal_newlines=True).splitlines()[1]
splits = dep.split(" - ")
return dict(
app_name=os.environ['OPENSHIFT_APP_NAME'],
url=os.environ['OPENSHIFT_APP_DNS'],
app_name=os.environ["OPENSHIFT_APP_NAME"],
url=os.environ["OPENSHIFT_APP_DNS"],
branch=splits[2],
commit_id=splits[3],
)
def send_bot_message(deployment: Dict[str, str]) -> None:
destination = config.deployment_notice_destination(deployment['branch'])
destination = config.deployment_notice_destination(deployment["branch"])
if destination is None:
# No message should be sent
return
@ -49,10 +49,10 @@ def send_bot_message(deployment: Dict[str, str]) -> None:
client.send_message(
{
'type': 'stream',
'to': destination['stream'],
'subject': destination['subject'],
'content': message,
"type": "stream",
"to": destination["stream"],
"subject": destination["subject"],
"content": message,
}
)

View file

@ -2,8 +2,8 @@
from typing import Dict, Optional, Text
# Change these values to configure authentication for the plugin
ZULIP_USER = 'openshift-bot@example.com'
ZULIP_API_KEY = '0123456789abcdef0123456789abcdef'
ZULIP_USER = "openshift-bot@example.com"
ZULIP_API_KEY = "0123456789abcdef0123456789abcdef"
# deployment_notice_destination() lets you customize where deployment notices
# are sent to with the full power of a Python function.
@ -20,8 +20,8 @@ ZULIP_API_KEY = '0123456789abcdef0123456789abcdef'
# * topic "master"
# And similarly for branch "test-post-receive" (for use when testing).
def deployment_notice_destination(branch: str) -> Optional[Dict[str, Text]]:
if branch in ['master', 'test-post-receive']:
return dict(stream='deployments', subject='%s' % (branch,))
if branch in ["master", "test-post-receive"]:
return dict(stream="deployments", subject="%s" % (branch,))
# Return None for cases where you don't want a notice sent
return None
@ -39,14 +39,14 @@ def deployment_notice_destination(branch: str) -> Optional[Dict[str, Text]]:
# * dep_id = deployment id
# * dep_time = deployment timestamp
def format_deployment_message(
app_name: str = '',
url: str = '',
branch: str = '',
commit_id: str = '',
dep_id: str = '',
dep_time: str = '',
app_name: str = "",
url: str = "",
branch: str = "",
commit_id: str = "",
dep_id: str = "",
dep_time: str = "",
) -> str:
return 'Deployed commit `%s` (%s) in [%s](%s)' % (commit_id, branch, app_name, url)
return "Deployed commit `%s` (%s) in [%s](%s)" % (commit_id, branch, app_name, url)
## If properly installed, the Zulip API should be in your import
@ -54,4 +54,4 @@ def format_deployment_message(
ZULIP_API_PATH = None # type: Optional[str]
# Set this to your Zulip server's API URI
ZULIP_SITE = 'https://zulip.example.com'
ZULIP_SITE = "https://zulip.example.com"

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
'''Zulip notification change-commit hook.
"""Zulip notification change-commit hook.
In Perforce, The "change-commit" trigger is fired after a metadata has been
created, files have been transferred, and the changelist committed to the depot
@ -12,7 +12,7 @@ This specific trigger expects command-line arguments in the form:
For example:
1234 //depot/security/src/
'''
"""
import os
import os.path
@ -43,11 +43,11 @@ try:
changelist = int(sys.argv[1]) # type: int
changeroot = sys.argv[2] # type: str
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)
sys.exit(-1)
except ValueError:
print("First argument must be an integer.\n\n", end=' ', file=sys.stderr)
print("First argument must be an integer.\n\n", end=" ", file=sys.stderr)
print(__doc__, file=sys.stderr)
sys.exit(-1)
@ -79,7 +79,7 @@ if hasattr(config, "P4_WEB"):
if p4web is not None:
# linkify the change number
change = '[{change}]({p4web}/{change}?ac=10)'.format(p4web=p4web, change=change)
change = "[{change}]({p4web}/{change}?ac=10)".format(p4web=p4web, change=change)
message = """**{user}** committed revision @{change} to `{path}`.

View file

@ -29,7 +29,7 @@ P4_WEB: Optional[str] = None
# * stream "depot_subdirectory-commits"
# * subject "change_root"
def commit_notice_destination(path: Text, changelist: int) -> Optional[Dict[Text, Text]]:
dirs = path.split('/')
dirs = path.split("/")
if len(dirs) >= 4 and dirs[3] not in ("*", "..."):
directory = dirs[3]
else:

View file

@ -21,7 +21,7 @@ import feedparser
import zulip
VERSION = "0.9" # type: str
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")) # type: str
OLDNESS_THRESHOLD = 30 # type: int
usage = """Usage: Send summaries of RSS entries for your favorite feeds to Zulip.
@ -52,38 +52,38 @@ parser = zulip.add_default_arguments(
argparse.ArgumentParser(usage)
) # type: argparse.ArgumentParser
parser.add_argument(
'--stream',
dest='stream',
help='The stream to which to send RSS messages.',
"--stream",
dest="stream",
help="The stream to which to send RSS messages.",
default="rss",
action='store',
action="store",
)
parser.add_argument(
'--data-dir',
dest='data_dir',
help='The directory where feed metadata is stored',
"--data-dir",
dest="data_dir",
help="The directory where feed metadata is stored",
default=os.path.join(RSS_DATA_DIR),
action='store',
action="store",
)
parser.add_argument(
'--feed-file',
dest='feed_file',
help='The file containing a list of RSS feed URLs to follow, one URL per line',
"--feed-file",
dest="feed_file",
help="The file containing a list of RSS feed URLs to follow, one URL per line",
default=os.path.join(RSS_DATA_DIR, "rss-feeds"),
action='store',
action="store",
)
parser.add_argument(
'--unwrap',
dest='unwrap',
action='store_true',
help='Convert word-wrapped paragraphs into single lines',
"--unwrap",
dest="unwrap",
action="store_true",
help="Convert word-wrapped paragraphs into single lines",
default=False,
)
parser.add_argument(
'--math',
dest='math',
action='store_true',
help='Convert $ to $$ (for KaTeX processing)',
"--math",
dest="math",
action="store_true",
help="Convert $ to $$ (for KaTeX processing)",
default=False,
)
@ -137,7 +137,7 @@ class MLStripper(HTMLParser):
self.fed.append(data)
def get_data(self) -> str:
return ''.join(self.fed)
return "".join(self.fed)
def strip_tags(html: str) -> str:
@ -155,13 +155,13 @@ def compute_entry_hash(entry: Dict[str, Any]) -> str:
def unwrap_text(body: str) -> str:
# Replace \n by space if it is preceded and followed by a non-\n.
# Example: '\na\nb\nc\n\nd\n' -> '\na b c\n\nd\n'
return re.sub('(?<=[^\n])\n(?=[^\n])', ' ', body)
return re.sub("(?<=[^\n])\n(?=[^\n])", " ", body)
def elide_subject(subject: str) -> str:
MAX_TOPIC_LENGTH = 60
if len(subject) > MAX_TOPIC_LENGTH:
subject = subject[: MAX_TOPIC_LENGTH - 3].rstrip() + '...'
subject = subject[: MAX_TOPIC_LENGTH - 3].rstrip() + "..."
return subject
@ -178,7 +178,7 @@ def send_zulip(entry: Any, feed_name: str) -> Dict[str, Any]:
) # type: str
if opts.math:
content = content.replace('$', '$$')
content = content.replace("$", "$$")
message = {
"type": "stream",

View file

@ -43,7 +43,7 @@ entry = svn.log(path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number
0
] # type: Dict[Text, Any]
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"]
) # type: Text
destination = config.commit_notice_destination(path, rev) # type: Optional[Dict[Text, Text]]

View file

@ -19,7 +19,7 @@ ZULIP_API_KEY = "0123456789abcdef0123456789abcdef"
# * stream "commits"
# * topic "branch_name"
def commit_notice_destination(path: Text, commit: Text) -> Optional[Dict[Text, Text]]:
repo = path.split('/')[-1]
repo = path.split("/")[-1]
if repo not in ["evil-master-plan", "my-super-secret-repository"]:
return dict(stream="commits", subject="%s" % (repo,))

View file

@ -100,24 +100,24 @@ class ZulipPlugin(Component):
content = "%s updated %s" % (author, markdown_ticket_url(ticket))
if comment:
content += ' with comment: %s\n\n' % (markdown_block(comment),)
content += " with comment: %s\n\n" % (markdown_block(comment),)
else:
content += ":\n\n"
field_changes = []
for key, value in old_values.items():
if key == "description":
content += '- Changed %s from %s\n\nto %s' % (
content += "- Changed %s from %s\n\nto %s" % (
key,
markdown_block(value),
markdown_block(ticket.values.get(key)),
)
elif old_values.get(key) == "":
field_changes.append('%s: => **%s**' % (key, ticket.values.get(key)))
field_changes.append("%s: => **%s**" % (key, ticket.values.get(key)))
elif ticket.values.get(key) == "":
field_changes.append('%s: **%s** => ""' % (key, old_values.get(key)))
else:
field_changes.append(
'%s: **%s** => **%s**' % (key, old_values.get(key), ticket.values.get(key))
"%s: **%s** => **%s**" % (key, old_values.get(key), ticket.values.get(key))
)
content += ", ".join(field_changes)

View file

@ -25,22 +25,22 @@ def get_model_id(options):
"""
trello_api_url = 'https://api.trello.com/1/board/{}'.format(options.trello_board_id)
trello_api_url = "https://api.trello.com/1/board/{}".format(options.trello_board_id)
params = {
'key': options.trello_api_key,
'token': options.trello_token,
"key": options.trello_api_key,
"token": options.trello_token,
}
trello_response = requests.get(trello_api_url, params=params)
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)
board_info_json = trello_response.json()
return board_info_json['id']
return board_info_json["id"]
def get_webhook_id(options, id_model):
@ -55,27 +55,27 @@ def get_webhook_id(options, id_model):
"""
trello_api_url = 'https://api.trello.com/1/webhooks/'
trello_api_url = "https://api.trello.com/1/webhooks/"
data = {
'key': options.trello_api_key,
'token': options.trello_token,
'description': 'Webhook for Zulip integration (From Trello {} to Zulip)'.format(
"key": options.trello_api_key,
"token": options.trello_token,
"description": "Webhook for Zulip integration (From Trello {} to Zulip)".format(
options.trello_board_name,
),
'callbackURL': options.zulip_webhook_url,
'idModel': id_model,
"callbackURL": options.zulip_webhook_url,
"idModel": id_model,
}
trello_response = requests.post(trello_api_url, data=data)
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)
webhook_info_json = trello_response.json()
return webhook_info_json['id']
return webhook_info_json["id"]
def create_webhook(options):
@ -88,20 +88,20 @@ def create_webhook(options):
"""
# first, we need to get the idModel
print('Getting Trello idModel for the {} board...'.format(options.trello_board_name))
print("Getting Trello idModel for the {} board...".format(options.trello_board_name))
id_model = get_model_id(options)
if id_model:
print('Success! The idModel is', id_model)
print("Success! The idModel is", id_model)
id_webhook = get_webhook_id(options, id_model)
if id_webhook:
print('Success! The webhook ID is', id_webhook)
print("Success! The webhook ID is", id_webhook)
print(
'Success! The webhook for the {} Trello board was successfully created.'.format(
"Success! The webhook for the {} Trello board was successfully created.".format(
options.trello_board_name
)
)
@ -118,36 +118,36 @@ at <https://zulip.com/integrations/doc/trello>.
"""
parser = argparse.ArgumentParser(description=description)
parser.add_argument('--trello-board-name', required=True, help='The Trello board name.')
parser.add_argument("--trello-board-name", required=True, help="The Trello board name.")
parser.add_argument(
'--trello-board-id',
"--trello-board-id",
required=True,
help=('The Trello board short ID. Can usually be found ' 'in the URL of the Trello board.'),
help=("The Trello board short ID. Can usually be found " "in the URL of the Trello board."),
)
parser.add_argument(
'--trello-api-key',
"--trello-api-key",
required=True,
help=(
'Visit https://trello.com/1/appkey/generate to generate '
'an APPLICATION_KEY (need to be logged into Trello).'
"Visit https://trello.com/1/appkey/generate to generate "
"an APPLICATION_KEY (need to be logged into Trello)."
),
)
parser.add_argument(
'--trello-token',
"--trello-token",
required=True,
help=(
'Visit https://trello.com/1/appkey/generate and under '
'`Developer API Keys`, click on `Token` and generate '
'a Trello access token.'
"Visit https://trello.com/1/appkey/generate and under "
"`Developer API Keys`, click on `Token` and generate "
"a Trello access token."
),
)
parser.add_argument(
'--zulip-webhook-url', required=True, help='The webhook URL that Trello will query.'
"--zulip-webhook-url", required=True, help="The webhook URL that Trello will query."
)
options = parser.parse_args()
create_webhook(options)
if __name__ == '__main__':
if __name__ == "__main__":
main()

View file

@ -69,32 +69,32 @@ access token" as well. Fill in the values displayed.
def write_config(config: ConfigParser, configfile_path: str) -> None:
with open(configfile_path, 'w') as configfile:
with open(configfile_path, "w") as configfile:
config.write(configfile)
parser = zulip.add_default_arguments(argparse.ArgumentParser("Fetch tweets from Twitter."))
parser.add_argument(
'--instructions',
action='store_true',
help='Show instructions for the twitter bot setup and exit',
"--instructions",
action="store_true",
help="Show instructions for the twitter bot setup and exit",
)
parser.add_argument(
'--limit-tweets', default=15, type=int, help='Maximum number of tweets to send at once'
"--limit-tweets", default=15, type=int, help="Maximum number of tweets to send at once"
)
parser.add_argument('--search', dest='search_terms', help='Terms to search on', action='store')
parser.add_argument("--search", dest="search_terms", help="Terms to search on", action="store")
parser.add_argument(
'--stream',
dest='stream',
help='The stream to which to send tweets',
"--stream",
dest="stream",
help="The stream to which to send tweets",
default="twitter",
action='store',
action="store",
)
parser.add_argument(
'--twitter-name', dest='twitter_name', help='Twitter username to poll new tweets from"'
"--twitter-name", dest="twitter_name", help='Twitter username to poll new tweets from"'
)
parser.add_argument('--excluded-terms', dest='excluded_terms', help='Terms to exclude tweets on')
parser.add_argument('--excluded-users', dest='excluded_users', help='Users to exclude tweets on')
parser.add_argument("--excluded-terms", dest="excluded_terms", help="Terms to exclude tweets on")
parser.add_argument("--excluded-users", dest="excluded_users", help="Users to exclude tweets on")
opts = parser.parse_args()
@ -103,15 +103,15 @@ if opts.instructions:
sys.exit()
if all([opts.search_terms, opts.twitter_name]):
parser.error('You must only specify either a search term or a username.')
parser.error("You must only specify either a search term or a username.")
if opts.search_terms:
client_type = 'ZulipTwitterSearch/'
client_type = "ZulipTwitterSearch/"
CONFIGFILE_INTERNAL = os.path.expanduser("~/.zulip_twitterrc_fetchsearch")
elif opts.twitter_name:
client_type = 'ZulipTwitter/'
client_type = "ZulipTwitter/"
CONFIGFILE_INTERNAL = os.path.expanduser("~/.zulip_twitteruserrc_fetchuser")
else:
parser.error('You must either specify a search term or a username.')
parser.error("You must either specify a search term or a username.")
try:
config = ConfigParser()
@ -119,10 +119,10 @@ try:
config_internal = ConfigParser()
config_internal.read(CONFIGFILE_INTERNAL)
consumer_key = config.get('twitter', 'consumer_key')
consumer_secret = config.get('twitter', 'consumer_secret')
access_token_key = config.get('twitter', 'access_token_key')
access_token_secret = config.get('twitter', 'access_token_secret')
consumer_key = config.get("twitter", "consumer_key")
consumer_secret = config.get("twitter", "consumer_secret")
access_token_key = config.get("twitter", "access_token_key")
access_token_secret = config.get("twitter", "access_token_secret")
except (NoSectionError, NoOptionError):
parser.error("Please provide a ~/.zulip_twitterrc")
@ -130,17 +130,17 @@ if not all([consumer_key, consumer_secret, access_token_key, access_token_secret
parser.error("Please provide a ~/.zulip_twitterrc")
try:
since_id = config_internal.getint('twitter', 'since_id')
since_id = config_internal.getint("twitter", "since_id")
except (NoOptionError, NoSectionError):
since_id = 0
try:
previous_twitter_name = config_internal.get('twitter', 'twitter_name')
previous_twitter_name = config_internal.get("twitter", "twitter_name")
except (NoOptionError, NoSectionError):
previous_twitter_name = ''
previous_twitter_name = ""
try:
previous_search_terms = config_internal.get('twitter', 'search_terms')
previous_search_terms = config_internal.get("twitter", "search_terms")
except (NoOptionError, NoSectionError):
previous_search_terms = ''
previous_search_terms = ""
try:
import twitter
@ -242,17 +242,17 @@ for status in statuses[::-1][: opts.limit_tweets]:
ret = client.send_message(message)
if ret['result'] == 'error':
if ret["result"] == "error":
# If sending failed (e.g. no such stream), abort and retry next time
print("Error sending message to zulip: %s" % ret['msg'])
print("Error sending message to zulip: %s" % ret["msg"])
break
else:
since_id = status.id
if 'twitter' not in config_internal.sections():
config_internal.add_section('twitter')
config_internal.set('twitter', 'since_id', str(since_id))
config_internal.set('twitter', 'search_terms', str(opts.search_terms))
config_internal.set('twitter', 'twitter_name', str(opts.twitter_name))
if "twitter" not in config_internal.sections():
config_internal.add_section("twitter")
config_internal.set("twitter", "since_id", str(since_id))
config_internal.set("twitter", "search_terms", str(opts.search_terms))
config_internal.set("twitter", "twitter_name", str(opts.twitter_name))
write_config(config_internal, CONFIGFILE_INTERNAL)

View file

@ -13,12 +13,12 @@ import zephyr
import zulip
parser = optparse.OptionParser()
parser.add_option('--verbose', dest='verbose', default=False, action='store_true')
parser.add_option('--site', dest='site', default=None, action='store')
parser.add_option('--sharded', default=False, action='store_true')
parser.add_option("--verbose", dest="verbose", default=False, action="store_true")
parser.add_option("--site", dest="site", default=None, action="store")
parser.add_option("--sharded", default=False, action="store_true")
(options, args) = parser.parse_args()
mit_user = 'tabbott/extra@ATHENA.MIT.EDU'
mit_user = "tabbott/extra@ATHENA.MIT.EDU"
zulip_client = zulip.Client(verbose=True, client="ZulipMonitoring/0.1", site=options.site)
@ -116,11 +116,11 @@ def send_zephyr(zwrite_args: List[str], content: str) -> bool:
# Subscribe to Zulip
try:
res = zulip_client.register(event_types=["message"])
if 'error' in res['result']:
if "error" in res["result"]:
logging.error("Error subscribing to Zulips!")
logging.error(res['msg'])
logging.error(res["msg"])
print_status_and_exit(1)
queue_id, last_event_id = (res['queue_id'], res['last_event_id'])
queue_id, last_event_id = (res["queue_id"], res["last_event_id"])
except Exception:
logger.exception("Unexpected error subscribing to Zulips")
print_status_and_exit(1)
@ -129,9 +129,9 @@ except Exception:
zephyr_subs_to_add = []
for (stream, test) in test_streams:
if stream == "message":
zephyr_subs_to_add.append((stream, 'personal', mit_user))
zephyr_subs_to_add.append((stream, "personal", mit_user))
else:
zephyr_subs_to_add.append((stream, '*', '*'))
zephyr_subs_to_add.append((stream, "*", "*"))
actually_subscribed = False
for tries in range(10):
@ -263,11 +263,11 @@ logger.info("Starting receiving messages!")
# receive zulips
res = zulip_client.get_events(queue_id=queue_id, last_event_id=last_event_id)
if 'error' in res['result']:
if "error" in res["result"]:
logging.error("Error receiving Zulips!")
logging.error(res['msg'])
logging.error(res["msg"])
print_status_and_exit(1)
messages = [event['message'] for event in res['events']]
messages = [event["message"] for event in res["events"]]
logger.info("Finished receiving Zulip messages!")
receive_zephyrs()
@ -296,7 +296,7 @@ def process_keys(content_list: List[str]) -> Tuple[Dict[str, int], Set[str], Set
# The h_foo variables are about the messages we _received_ in Zulip
# The z_foo variables are about the messages we _received_ in Zephyr
h_contents = [message["content"] for message in messages]
z_contents = [notice.message.split('\0')[1] for notice in notices]
z_contents = [notice.message.split("\0")[1] for notice in notices]
(h_key_counts, h_missing_z, h_missing_h, h_duplicates, h_success) = process_keys(h_contents)
(z_key_counts, z_missing_z, z_missing_h, z_duplicates, z_success) = process_keys(z_contents)

View file

@ -6,7 +6,7 @@ import os
import sys
import unicodedata
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'api'))
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "api"))
import zulip
@ -18,20 +18,20 @@ def write_public_streams() -> None:
# normalization and then lower-casing server-side
canonical_cls = unicodedata.normalize("NFKC", stream_name).lower()
if canonical_cls in [
'security',
'login',
'network',
'ops',
'user_locate',
'mit',
'moof',
'wsmonitor',
'wg_ctl',
'winlogger',
'hm_ctl',
'hm_stat',
'zephyr_admin',
'zephyr_ctl',
"security",
"login",
"network",
"ops",
"user_locate",
"mit",
"moof",
"wsmonitor",
"wg_ctl",
"winlogger",
"hm_ctl",
"hm_stat",
"zephyr_admin",
"zephyr_ctl",
]:
# These zephyr classes cannot be subscribed to by us, due
# to MIT's Zephyr access control settings

View file

@ -39,8 +39,8 @@ def to_zulip_username(zephyr_username: str) -> str:
(user, realm) = (zephyr_username, "ATHENA.MIT.EDU")
if realm.upper() == "ATHENA.MIT.EDU":
# Hack to make ctl's fake username setup work :)
if user.lower() == 'golem':
user = 'ctl'
if user.lower() == "golem":
user = "ctl"
return user.lower() + "@mit.edu"
return user.lower() + "|" + realm.upper() + "@mit.edu"
@ -49,10 +49,10 @@ def to_zephyr_username(zulip_username: str) -> str:
(user, realm) = zulip_username.split("@")
if "|" not in user:
# Hack to make ctl's fake username setup work :)
if user.lower() == 'ctl':
user = 'golem'
if user.lower() == "ctl":
user = "golem"
return user.lower() + "@ATHENA.MIT.EDU"
match_user = re.match(r'([a-zA-Z0-9_]+)\|(.+)', user)
match_user = re.match(r"([a-zA-Z0-9_]+)\|(.+)", user)
if not match_user:
raise Exception("Could not parse Zephyr realm for cross-realm user %s" % (zulip_username,))
return match_user.group(1).lower() + "@" + match_user.group(2).upper()
@ -85,14 +85,14 @@ def unwrap_lines(body: str) -> str:
previous_line = lines[0]
for line in lines[1:]:
line = line.rstrip()
if re.match(r'^\W', line, flags=re.UNICODE) and re.match(
r'^\W', previous_line, flags=re.UNICODE
if re.match(r"^\W", line, flags=re.UNICODE) and re.match(
r"^\W", previous_line, flags=re.UNICODE
):
result += previous_line + "\n"
elif (
line == ""
or previous_line == ""
or re.match(r'^\W', line, flags=re.UNICODE)
or re.match(r"^\W", line, flags=re.UNICODE)
or different_paragraph(previous_line, line)
):
# Use 2 newlines to separate sections so that we
@ -122,31 +122,31 @@ def send_zulip(zeph: ZephyrDict) -> Dict[str, Any]:
message = {}
if options.forward_class_messages:
message["forged"] = "yes"
message['type'] = zeph['type']
message['time'] = zeph['time']
message['sender'] = to_zulip_username(zeph['sender'])
message["type"] = zeph["type"]
message["time"] = zeph["time"]
message["sender"] = to_zulip_username(zeph["sender"])
if "subject" in zeph:
# Truncate the subject to the current limit in Zulip. No
# need to do this for stream names, since we're only
# subscribed to valid stream names.
message["subject"] = zeph["subject"][:60]
if zeph['type'] == 'stream':
if zeph["type"] == "stream":
# Forward messages sent to -c foo -i bar to stream bar subject "instance"
if zeph["stream"] == "message":
message['to'] = zeph['subject'].lower()
message['subject'] = "instance %s" % (zeph['subject'],)
message["to"] = zeph["subject"].lower()
message["subject"] = "instance %s" % (zeph["subject"],)
elif zeph["stream"] == "tabbott-test5":
message['to'] = zeph['subject'].lower()
message['subject'] = "test instance %s" % (zeph['subject'],)
message["to"] = zeph["subject"].lower()
message["subject"] = "test instance %s" % (zeph["subject"],)
else:
message["to"] = zeph["stream"]
else:
message["to"] = zeph["recipient"]
message['content'] = unwrap_lines(zeph['content'])
message["content"] = unwrap_lines(zeph["content"])
if options.test_mode and options.site == DEFAULT_SITE:
logger.debug("Message is: %s" % (str(message),))
return {'result': "success"}
return {"result": "success"}
return zulip_client.send_message(message)
@ -311,13 +311,13 @@ def parse_zephyr_body(zephyr_data: str, notice_format: str) -> Tuple[str, str]:
try:
(zsig, body) = zephyr_data.split("\x00", 1)
if (
notice_format == 'New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4'
or notice_format == 'New transaction [$1] entered in $2\nFrom: $3\nSubject: $4'
notice_format == "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4"
or notice_format == "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4"
):
# Logic based off of owl_zephyr_get_message in barnowl
fields = body.split('\x00')
fields = body.split("\x00")
if len(fields) == 5:
body = 'New transaction [%s] entered in %s\nFrom: %s (%s)\nSubject: %s' % (
body = "New transaction [%s] entered in %s\nFrom: %s (%s)\nSubject: %s" % (
fields[0],
fields[1],
fields[2],
@ -327,7 +327,7 @@ def parse_zephyr_body(zephyr_data: str, notice_format: str) -> Tuple[str, str]:
except ValueError:
(zsig, body) = ("", zephyr_data)
# Clean body of any null characters, since they're invalid in our protocol.
body = body.replace('\x00', '')
body = body.replace("\x00", "")
return (zsig, body)
@ -350,8 +350,8 @@ def parse_crypt_table(zephyr_class: str, instance: str) -> Optional[str]:
continue
groups = match.groupdict()
if (
groups['class'].lower() == zephyr_class
and 'keypath' in groups
groups["class"].lower() == zephyr_class
and "keypath" in groups
and groups.get("algorithm") == "AES"
):
return groups["keypath"]
@ -453,23 +453,23 @@ def process_notice(notice: "zephyr.ZNotice", log: Optional[IO[str]]) -> None:
zeph: ZephyrDict
zeph = {
'time': str(notice.time),
'sender': notice.sender,
'zsig': zsig, # logged here but not used by app
'content': body,
"time": str(notice.time),
"sender": notice.sender,
"zsig": zsig, # logged here but not used by app
"content": body,
}
if is_huddle:
zeph['type'] = 'private'
zeph['recipient'] = huddle_recipients
zeph["type"] = "private"
zeph["recipient"] = huddle_recipients
elif is_personal:
assert notice.recipient is not None
zeph['type'] = 'private'
zeph['recipient'] = to_zulip_username(notice.recipient)
zeph["type"] = "private"
zeph["recipient"] = to_zulip_username(notice.recipient)
else:
zeph['type'] = 'stream'
zeph['stream'] = zephyr_class
zeph["type"] = "stream"
zeph["stream"] = zephyr_class
if notice.instance.strip() != "":
zeph['subject'] = notice.instance
zeph["subject"] = notice.instance
else:
zeph["subject"] = '(instance "%s")' % (notice.instance,)
@ -489,7 +489,7 @@ def process_notice(notice: "zephyr.ZNotice", log: Optional[IO[str]]) -> None:
"Received a message on %s/%s from %s..." % (zephyr_class, notice.instance, notice.sender)
)
if log is not None:
log.write(json.dumps(zeph) + '\n')
log.write(json.dumps(zeph) + "\n")
log.flush()
if os.fork() == 0:
@ -593,7 +593,7 @@ def zephyr_to_zulip(options: optparse.Values) -> None:
zeph["subject"] = zeph["instance"]
logger.info(
"sending saved message to %s from %s..."
% (zeph.get('stream', zeph.get('recipient')), zeph['sender'])
% (zeph.get("stream", zeph.get("recipient")), zeph["sender"])
)
send_zulip(zeph)
except Exception:
@ -603,7 +603,7 @@ def zephyr_to_zulip(options: optparse.Values) -> None:
logger.info("Successfully initialized; Starting receive loop.")
if options.resend_log_path is not None:
with open(options.resend_log_path, 'a') as log:
with open(options.resend_log_path, "a") as log:
process_loop(log)
else:
process_loop(None)
@ -700,10 +700,10 @@ Feedback button or at support@zulip.com."""
]
# Hack to make ctl's fake username setup work :)
if message['type'] == "stream" and zulip_account_email == "ctl@mit.edu":
if message["type"] == "stream" and zulip_account_email == "ctl@mit.edu":
zwrite_args.extend(["-S", "ctl"])
if message['type'] == "stream":
if message["type"] == "stream":
zephyr_class = message["display_recipient"]
instance = message["subject"]
@ -725,11 +725,11 @@ Feedback button or at support@zulip.com."""
zephyr_class = "message"
zwrite_args.extend(["-c", zephyr_class, "-i", instance])
logger.info("Forwarding message to class %s, instance %s" % (zephyr_class, instance))
elif message['type'] == "private":
if len(message['display_recipient']) == 1:
elif message["type"] == "private":
if len(message["display_recipient"]) == 1:
recipient = to_zephyr_username(message["display_recipient"][0]["email"])
recipients = [recipient]
elif len(message['display_recipient']) == 2:
elif len(message["display_recipient"]) == 2:
recipient = ""
for r in message["display_recipient"]:
if r["email"].lower() != zulip_account_email.lower():
@ -1085,62 +1085,62 @@ def configure_logger(logger: logging.Logger, direction_name: Optional[str]) -> N
def parse_args() -> Tuple[optparse.Values, List[str]]:
parser = optparse.OptionParser()
parser.add_option(
'--forward-class-messages', default=False, help=optparse.SUPPRESS_HELP, action='store_true'
"--forward-class-messages", default=False, help=optparse.SUPPRESS_HELP, action="store_true"
)
parser.add_option('--shard', help=optparse.SUPPRESS_HELP)
parser.add_option('--noshard', default=False, help=optparse.SUPPRESS_HELP, action='store_true')
parser.add_option('--resend-log', dest='logs_to_resend', help=optparse.SUPPRESS_HELP)
parser.add_option('--enable-resend-log', dest='resend_log_path', help=optparse.SUPPRESS_HELP)
parser.add_option('--log-path', dest='log_path', help=optparse.SUPPRESS_HELP)
parser.add_option("--shard", help=optparse.SUPPRESS_HELP)
parser.add_option("--noshard", default=False, help=optparse.SUPPRESS_HELP, action="store_true")
parser.add_option("--resend-log", dest="logs_to_resend", help=optparse.SUPPRESS_HELP)
parser.add_option("--enable-resend-log", dest="resend_log_path", help=optparse.SUPPRESS_HELP)
parser.add_option("--log-path", dest="log_path", help=optparse.SUPPRESS_HELP)
parser.add_option(
'--stream-file-path',
dest='stream_file_path',
"--stream-file-path",
dest="stream_file_path",
default="/home/zulip/public_streams",
help=optparse.SUPPRESS_HELP,
)
parser.add_option(
'--no-forward-personals',
dest='forward_personals',
"--no-forward-personals",
dest="forward_personals",
help=optparse.SUPPRESS_HELP,
default=True,
action='store_false',
action="store_false",
)
parser.add_option(
'--forward-mail-zephyrs',
dest='forward_mail_zephyrs',
"--forward-mail-zephyrs",
dest="forward_mail_zephyrs",
help=optparse.SUPPRESS_HELP,
default=False,
action='store_true',
action="store_true",
)
parser.add_option(
'--no-forward-from-zulip',
"--no-forward-from-zulip",
default=True,
dest='forward_from_zulip',
dest="forward_from_zulip",
help=optparse.SUPPRESS_HELP,
action='store_false',
action="store_false",
)
parser.add_option('--verbose', default=False, help=optparse.SUPPRESS_HELP, action='store_true')
parser.add_option('--sync-subscriptions', default=False, action='store_true')
parser.add_option('--ignore-expired-tickets', default=False, action='store_true')
parser.add_option('--site', default=DEFAULT_SITE, help=optparse.SUPPRESS_HELP)
parser.add_option('--on-startup-command', default=None, help=optparse.SUPPRESS_HELP)
parser.add_option('--user', default=os.environ["USER"], help=optparse.SUPPRESS_HELP)
parser.add_option("--verbose", default=False, help=optparse.SUPPRESS_HELP, action="store_true")
parser.add_option("--sync-subscriptions", default=False, action="store_true")
parser.add_option("--ignore-expired-tickets", default=False, action="store_true")
parser.add_option("--site", default=DEFAULT_SITE, help=optparse.SUPPRESS_HELP)
parser.add_option("--on-startup-command", default=None, help=optparse.SUPPRESS_HELP)
parser.add_option("--user", default=os.environ["USER"], help=optparse.SUPPRESS_HELP)
parser.add_option(
'--stamp-path',
"--stamp-path",
default="/afs/athena.mit.edu/user/t/a/tabbott/for_friends",
help=optparse.SUPPRESS_HELP,
)
parser.add_option('--session-path', default=None, help=optparse.SUPPRESS_HELP)
parser.add_option('--nagios-class', default=None, help=optparse.SUPPRESS_HELP)
parser.add_option('--nagios-path', default=None, help=optparse.SUPPRESS_HELP)
parser.add_option("--session-path", default=None, help=optparse.SUPPRESS_HELP)
parser.add_option("--nagios-class", default=None, help=optparse.SUPPRESS_HELP)
parser.add_option("--nagios-path", default=None, help=optparse.SUPPRESS_HELP)
parser.add_option(
'--use-sessions', default=False, action='store_true', help=optparse.SUPPRESS_HELP
"--use-sessions", default=False, action="store_true", help=optparse.SUPPRESS_HELP
)
parser.add_option(
'--test-mode', default=False, help=optparse.SUPPRESS_HELP, action='store_true'
"--test-mode", default=False, help=optparse.SUPPRESS_HELP, action="store_true"
)
parser.add_option(
'--api-key-file', default=os.path.join(os.environ["HOME"], "Private", ".humbug-api-key")
"--api-key-file", default=os.path.join(os.environ["HOME"], "Private", ".humbug-api-key")
)
return parser.parse_args()
@ -1235,7 +1235,7 @@ or specify the --api-key-file option."""
# Personals mirror on behalf of another user.
pgrep_query = "%s.*--user=%s" % (pgrep_query, options.user)
proc = subprocess.Popen(
['pgrep', '-U', os.environ["USER"], "-f", pgrep_query],
["pgrep", "-U", os.environ["USER"], "-f", pgrep_query],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

View file

@ -15,7 +15,7 @@ def version() -> str:
version_line = next(
itertools.dropwhile(lambda x: not x.startswith("__version__"), in_handle)
)
version = version_line.split('=')[-1].strip().replace('"', '')
version = version_line.split("=")[-1].strip().replace('"', "")
return version
@ -28,50 +28,50 @@ def recur_expand(target_root: Any, dir: Any) -> Generator[Tuple[str, List[str]],
# We should be installable with either setuptools or distutils.
package_info = dict(
name='zulip',
name="zulip",
version=version(),
description='Bindings for the Zulip message API',
description="Bindings for the Zulip message API",
long_description=long_description,
long_description_content_type="text/markdown",
author='Zulip Open Source Project',
author_email='zulip-devel@googlegroups.com',
author="Zulip Open Source Project",
author_email="zulip-devel@googlegroups.com",
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Topic :: Communications :: Chat',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
"Development Status :: 4 - Beta",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Topic :: Communications :: Chat",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
],
python_requires='>=3.6',
url='https://www.zulip.org/',
python_requires=">=3.6",
url="https://www.zulip.org/",
project_urls={
"Source": "https://github.com/zulip/python-zulip-api/",
"Documentation": "https://zulip.com/api",
},
data_files=list(recur_expand('share/zulip', 'integrations')),
data_files=list(recur_expand("share/zulip", "integrations")),
include_package_data=True,
entry_points={
'console_scripts': [
'zulip-send=zulip.send:main',
'zulip-api-examples=zulip.api_examples:main',
'zulip-matrix-bridge=integrations.bridge_with_matrix.matrix_bridge:main',
'zulip-api=zulip.cli:cli',
"console_scripts": [
"zulip-send=zulip.send:main",
"zulip-api-examples=zulip.api_examples:main",
"zulip-matrix-bridge=integrations.bridge_with_matrix.matrix_bridge:main",
"zulip-api=zulip.cli:cli",
],
},
package_data={'zulip': ["py.typed"]},
package_data={"zulip": ["py.typed"]},
) # type: Dict[str, Any]
setuptools_info = dict(
install_requires=[
'requests[security]>=0.12.1',
'matrix_client',
'distro',
'click',
"requests[security]>=0.12.1",
"matrix_client",
"distro",
"click",
],
)
@ -79,7 +79,7 @@ try:
from setuptools import find_packages, setup
package_info.update(setuptools_info)
package_info['packages'] = find_packages(exclude=['tests'])
package_info["packages"] = find_packages(exclude=["tests"])
except ImportError:
from distutils.core import setup
@ -89,12 +89,12 @@ except ImportError:
try:
import requests
assert LooseVersion(requests.__version__) >= LooseVersion('0.12.1')
assert LooseVersion(requests.__version__) >= LooseVersion("0.12.1")
except (ImportError, AssertionError):
print("requests >=0.12.1 is not installed", file=sys.stderr)
sys.exit(1)
package_info['packages'] = ['zulip']
package_info["packages"] = ["zulip"]
setup(**package_info)

View file

@ -15,8 +15,8 @@ class TestDefaultArguments(TestCase):
def test_invalid_arguments(self) -> None:
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage="lorem ipsum"))
with self.assertRaises(SystemExit) as cm:
with patch('sys.stderr', new=io.StringIO()) as mock_stderr:
parser.parse_args(['invalid argument'])
with patch("sys.stderr", new=io.StringIO()) as mock_stderr:
parser.parse_args(["invalid argument"])
self.assertEqual(cm.exception.code, 2)
# Assert that invalid arguments exit with printing the full usage (non-standard behavior)
self.assertTrue(
@ -32,20 +32,20 @@ Zulip API configuration:
)
)
@patch('os.path.exists', return_value=False)
@patch("os.path.exists", return_value=False)
def test_config_path_with_tilde(self, mock_os_path_exists: bool) -> None:
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage="lorem ipsum"))
test_path = '~/zuliprc'
args = parser.parse_args(['--config-file', test_path])
test_path = "~/zuliprc"
args = parser.parse_args(["--config-file", test_path])
with self.assertRaises(ZulipError) as cm:
zulip.init_from_options(args)
expanded_test_path = os.path.abspath(os.path.expanduser(test_path))
self.assertEqual(
str(cm.exception),
'api_key or email not specified and '
'file {} does not exist'.format(expanded_test_path),
"api_key or email not specified and "
"file {} does not exist".format(expanded_test_path),
)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View file

@ -9,17 +9,17 @@ import zulip
class TestHashUtilDecode(TestCase):
def test_hash_util_decode(self) -> None:
tests = [
('topic', 'topic'),
('.2Edot', '.dot'),
('.23stream.20name', '#stream name'),
('(no.20topic)', '(no topic)'),
('.3Cstrong.3Ebold.3C.2Fstrong.3E', '<strong>bold</strong>'),
('.3Asome_emoji.3A', ':some_emoji:'),
("topic", "topic"),
(".2Edot", ".dot"),
(".23stream.20name", "#stream name"),
("(no.20topic)", "(no topic)"),
(".3Cstrong.3Ebold.3C.2Fstrong.3E", "<strong>bold</strong>"),
(".3Asome_emoji.3A", ":some_emoji:"),
]
for encoded_string, decoded_string in tests:
with self.subTest(encoded_string=encoded_string):
self.assertEqual(zulip.hash_util_decode(encoded_string), decoded_string)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

File diff suppressed because it is too large Load diff

View file

@ -11,11 +11,11 @@ def main() -> None:
Prints the path to the Zulip API example scripts."""
parser = argparse.ArgumentParser(usage=usage)
parser.add_argument(
'script_name', nargs='?', default='', help='print path to the script <script_name>'
"script_name", nargs="?", default="", help="print path to the script <script_name>"
)
args = parser.parse_args()
zulip_path = os.path.abspath(os.path.dirname(zulip.__file__))
examples_path = os.path.abspath(os.path.join(zulip_path, 'examples', args.script_name))
examples_path = os.path.abspath(os.path.join(zulip_path, "examples", args.script_name))
if os.path.isdir(examples_path) or (args.script_name and os.path.isfile(examples_path)):
print(examples_path)
else:
@ -26,5 +26,5 @@ Prints the path to the Zulip API example scripts."""
)
if __name__ == '__main__':
if __name__ == "__main__":
main()

View file

@ -14,17 +14,17 @@ Example: alert-words remove banana
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('operation', choices=['get', 'add', 'remove'], type=str)
parser.add_argument('words', type=str, nargs='*')
parser.add_argument("operation", choices=["get", "add", "remove"], type=str)
parser.add_argument("words", type=str, nargs="*")
options = parser.parse_args()
client = zulip.init_from_options(options)
if options.operation == 'get':
if options.operation == "get":
result = client.get_alert_words()
elif options.operation == 'add':
elif options.operation == "add":
result = client.add_alert_words(options.words)
elif options.operation == 'remove':
elif options.operation == "remove":
result = client.remove_alert_words(options.words)
print(result)

View file

@ -15,10 +15,10 @@ Specify your Zulip API credentials and server in a ~/.zuliprc file or using the
import zulip
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--new-email', required=True)
parser.add_argument('--new-password', required=True)
parser.add_argument('--new-full-name', required=True)
parser.add_argument('--new-short-name', required=True)
parser.add_argument("--new-email", required=True)
parser.add_argument("--new-password", required=True)
parser.add_argument("--new-full-name", required=True)
parser.add_argument("--new-short-name", required=True)
options = parser.parse_args()
client = zulip.init_from_options(options)
@ -26,10 +26,10 @@ client = zulip.init_from_options(options)
print(
client.create_user(
{
'email': options.new_email,
'password': options.new_password,
'full_name': options.new_full_name,
'short_name': options.new_short_name,
"email": options.new_email,
"password": options.new_password,
"full_name": options.new_full_name,
"short_name": options.new_short_name,
}
)
)

View file

@ -13,7 +13,7 @@ Example: delete-message 42
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('message_id', type=int)
parser.add_argument("message_id", type=int)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -11,7 +11,7 @@ Example: delete-stream 42
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('stream_id', type=int)
parser.add_argument("stream_id", type=int)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -15,9 +15,9 @@ Specify your Zulip API credentials and server in a ~/.zuliprc file or using the
import zulip
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--message-id', type=int, required=True)
parser.add_argument('--subject', default="")
parser.add_argument('--content', default="")
parser.add_argument("--message-id", type=int, required=True)
parser.add_argument("--subject", default="")
parser.add_argument("--content", default="")
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -19,12 +19,12 @@ def quote(string: str) -> str:
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--stream-id', type=int, required=True)
parser.add_argument('--description')
parser.add_argument('--new-name')
parser.add_argument('--private', action='store_true')
parser.add_argument('--announcement-only', action='store_true')
parser.add_argument('--history-public-to-subscribers', action='store_true')
parser.add_argument("--stream-id", type=int, required=True)
parser.add_argument("--description")
parser.add_argument("--new-name")
parser.add_argument("--private", action="store_true")
parser.add_argument("--announcement-only", action="store_true")
parser.add_argument("--history-public-to-subscribers", action="store_true")
options = parser.parse_args()
client = zulip.init_from_options(options)
@ -32,12 +32,12 @@ client = zulip.init_from_options(options)
print(
client.update_stream(
{
'stream_id': options.stream_id,
'description': quote(options.description),
'new_name': quote(options.new_name),
'is_private': options.private,
'is_announcement_only': options.announcement_only,
'history_public_to_subscribers': options.history_public_to_subscribers,
"stream_id": options.stream_id,
"description": quote(options.description),
"new_name": quote(options.new_name),
"is_private": options.private,
"is_announcement_only": options.announcement_only,
"history_public_to_subscribers": options.history_public_to_subscribers,
}
)
)

View file

@ -13,11 +13,11 @@ and store them in JSON format.
Example: get-history --stream announce --topic important"""
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--stream', required=True, help="The stream name to get the history")
parser.add_argument('--topic', help="The topic name to get the history")
parser.add_argument("--stream", required=True, help="The stream name to get the history")
parser.add_argument("--topic", help="The topic name to get the history")
parser.add_argument(
'--filename',
default='history.json',
"--filename",
default="history.json",
help="The file name to store the fetched \
history.\n Default 'history.json'",
)
@ -25,19 +25,19 @@ options = parser.parse_args()
client = zulip.init_from_options(options)
narrow = [{'operator': 'stream', 'operand': options.stream}]
narrow = [{"operator": "stream", "operand": options.stream}]
if options.topic:
narrow.append({'operator': 'topic', 'operand': options.topic})
narrow.append({"operator": "topic", "operand": options.topic})
request = {
# Initially we have the anchor as 0, so that it starts fetching
# from the oldest message in the narrow
'anchor': 0,
'num_before': 0,
'num_after': 1000,
'narrow': narrow,
'client_gravatar': False,
'apply_markdown': False,
"anchor": 0,
"num_before": 0,
"num_after": 1000,
"narrow": narrow,
"client_gravatar": False,
"apply_markdown": False,
}
all_messages = [] # type: List[Dict[str, Any]]
@ -47,17 +47,17 @@ while not found_newest:
result = client.get_messages(request)
try:
found_newest = result["found_newest"]
if result['messages']:
if result["messages"]:
# Setting the anchor to the next immediate message after the last fetched message.
request['anchor'] = result['messages'][-1]['id'] + 1
request["anchor"] = result["messages"][-1]["id"] + 1
all_messages.extend(result["messages"])
except KeyError:
# Might occur when the request is not returned with a success status
print('Error occured: Payload was:')
print("Error occured: Payload was:")
print(result)
quit()
with open(options.filename, "w+") as f:
print('Writing %d messages...' % len(all_messages))
print("Writing %d messages..." % len(all_messages))
f.write(json.dumps(all_messages))

View file

@ -17,13 +17,13 @@ Example: get-messages --use-first-unread-anchor --num-before=5 \\
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--anchor', type=int)
parser.add_argument('--use-first-unread-anchor', action='store_true')
parser.add_argument('--num-before', type=int, required=True)
parser.add_argument('--num-after', type=int, required=True)
parser.add_argument('--client-gravatar', action='store_true')
parser.add_argument('--apply-markdown', action='store_true')
parser.add_argument('--narrow')
parser.add_argument("--anchor", type=int)
parser.add_argument("--use-first-unread-anchor", action="store_true")
parser.add_argument("--num-before", type=int, required=True)
parser.add_argument("--num-after", type=int, required=True)
parser.add_argument("--client-gravatar", action="store_true")
parser.add_argument("--apply-markdown", action="store_true")
parser.add_argument("--narrow")
options = parser.parse_args()
client = zulip.init_from_options(options)
@ -31,13 +31,13 @@ client = zulip.init_from_options(options)
print(
client.get_messages(
{
'anchor': options.anchor,
'use_first_unread_anchor': options.use_first_unread_anchor,
'num_before': options.num_before,
'num_after': options.num_after,
'narrow': options.narrow,
'client_gravatar': options.client_gravatar,
'apply_markdown': options.apply_markdown,
"anchor": options.anchor,
"use_first_unread_anchor": options.use_first_unread_anchor,
"num_before": options.num_before,
"num_after": options.num_after,
"narrow": options.narrow,
"client_gravatar": options.client_gravatar,
"apply_markdown": options.apply_markdown,
}
)
)

View file

@ -12,7 +12,7 @@ Example: get-raw-message 42
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('message_id', type=int)
parser.add_argument("message_id", type=int)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -10,7 +10,7 @@ Get all the topics for a specific stream.
import zulip
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--stream-id', required=True)
parser.add_argument("--stream-id", required=True)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -10,7 +10,7 @@ Get presence data for another user.
import zulip
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--email', required=True)
parser.add_argument("--email", required=True)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -10,7 +10,7 @@ Example: message-history 42
"""
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('message_id', type=int)
parser.add_argument("message_id", type=int)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -11,17 +11,17 @@ Example: mute-topic unmute Denmark party
"""
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('op', choices=['mute', 'unmute'])
parser.add_argument('stream')
parser.add_argument('topic')
parser.add_argument("op", choices=["mute", "unmute"])
parser.add_argument("stream")
parser.add_argument("topic")
options = parser.parse_args()
client = zulip.init_from_options(options)
OPERATIONS = {'mute': 'add', 'unmute': 'remove'}
OPERATIONS = {"mute": "add", "unmute": "remove"}
print(
client.mute_topic(
{'op': OPERATIONS[options.op], 'stream': options.stream, 'topic': options.topic}
{"op": OPERATIONS[options.op], "stream": options.stream, "topic": options.topic}
)
)

View file

@ -12,18 +12,18 @@ Example: send-message --type=stream commits --subject="my subject" --message="te
Example: send-message user1@example.com user2@example.com
"""
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('recipients', nargs='+')
parser.add_argument('--subject', default='test')
parser.add_argument('--message', default='test message')
parser.add_argument('--type', default='private')
parser.add_argument("recipients", nargs="+")
parser.add_argument("--subject", default="test")
parser.add_argument("--message", default="test message")
parser.add_argument("--type", default="private")
options = parser.parse_args()
client = zulip.init_from_options(options)
message_data = {
'type': options.type,
'content': options.message,
'subject': options.subject,
'to': options.recipients,
"type": options.type,
"content": options.message,
"subject": options.subject,
"to": options.recipients,
}
print(client.send_message(message_data))

View file

@ -15,7 +15,7 @@ Specify your Zulip API credentials and server in a ~/.zuliprc file or using the
import zulip
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--streams', action='store', required=True)
parser.add_argument("--streams", action="store", required=True)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -15,7 +15,7 @@ Specify your Zulip API credentials and server in a ~/.zuliprc file or using the
import zulip
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--streams', action='store', required=True)
parser.add_argument("--streams", action="store", required=True)
options = parser.parse_args()
client = zulip.init_from_options(options)

View file

@ -12,15 +12,15 @@ Example: update-message-flags remove starred 16 23 42
"""
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('op', choices=['add', 'remove'])
parser.add_argument('flag')
parser.add_argument('messages', type=int, nargs='+')
parser.add_argument("op", choices=["add", "remove"])
parser.add_argument("flag")
parser.add_argument("messages", type=int, nargs="+")
options = parser.parse_args()
client = zulip.init_from_options(options)
print(
client.update_message_flags(
{'op': options.op, 'flag': options.flag, 'messages': options.messages}
{"op": options.op, "flag": options.flag, "messages": options.messages}
)
)

View file

@ -8,7 +8,7 @@ import zulip
class StringIO(_StringIO):
name = '' # https://github.com/python/typeshed/issues/598
name = "" # https://github.com/python/typeshed/issues/598
usage = """upload-file [options]
@ -22,20 +22,20 @@ If no --file-path is specified, a placeholder text file will be used instead.
"""
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument('--file-path', required=True)
parser.add_argument("--file-path", required=True)
options = parser.parse_args()
client = zulip.init_from_options(options)
if options.file_path:
file = open(options.file_path, 'rb') # type: IO[Any]
file = open(options.file_path, "rb") # type: IO[Any]
else:
file = StringIO('This is a test file.')
file.name = 'test.txt'
file = StringIO("This is a test file.")
file.name = "test.txt"
response = client.upload_file(file)
try:
print('File URI: {}'.format(response['uri']))
print("File URI: {}".format(response["uri"]))
except KeyError:
print('Error! API response was: {}'.format(response))
print("Error! API response was: {}".format(response))

View file

@ -4,7 +4,7 @@ from typing import Any, Dict, List
import zulip
welcome_text = 'Hello {}, Welcome to Zulip!\n \
welcome_text = "Hello {}, Welcome to Zulip!\n \
* The first thing you should do is to install the development environment. \
We recommend following the vagrant setup as it is well documented and used \
by most of the contributors. If you face any trouble during installation \
@ -21,7 +21,7 @@ of the main projects you can contribute to are Zulip \
a [bot](https://github.com/zulip/zulipbot) that you can contribute to!!\n \
* We host our source code on GitHub. If you are not familiar with Git or \
GitHub checkout [this](http://zulip.readthedocs.io/en/latest/git-guide.html) \
guide. You don\'t have to learn everything but please go through it and learn \
guide. You don't have to learn everything but please go through it and learn \
the basics. We are here to help you if you are having any trouble. Post your \
questions in #git help . \
* Once you have completed these steps you can start contributing. You \
@ -33,55 +33,55 @@ but if you want a bite size issue for mobile or electron feel free post in #mobi
or #electron .\n \
* Solving the first issue can be difficult. The key is to not give up. If you spend \
enough time on the issue you should be able to solve it no matter what.\n \
* Use `grep` command when you can\'t figure out what files to change :) For example \
* Use `grep` command when you can't figure out what files to change :) For example \
if you want know what files to modify in order to change Invite more users to Add \
more users which you can see below the user status list, grep for "Invite more \
users" in terminal.\n \
* If you are stuck with something and can\'t figure out what to do you can ask \
more users which you can see below the user status list, grep for \"Invite more \
users\" in terminal.\n \
* If you are stuck with something and can't figure out what to do you can ask \
for help in #development help . But make sure that you tried your best to figure \
out the issue by yourself\n \
* If you are here for #Outreachy 2017-2018 or #GSoC don\'t worry much about \
* If you are here for #Outreachy 2017-2018 or #GSoC don't worry much about \
whether you will get selected or not. You will learn a lot contributing to \
Zulip in course of next few months and if you do a good job at that you \
will get selected too :)\n \
* Most important of all welcome to the Zulip family :octopus:'
* Most important of all welcome to the Zulip family :octopus:"
# These streams will cause the message to be sent
streams_to_watch = ['new members']
streams_to_watch = ["new members"]
# These streams will cause anyone who sends a message there to be removed from the watchlist
streams_to_cancel = ['development help']
streams_to_cancel = ["development help"]
def get_watchlist() -> List[Any]:
storage = client.get_storage()
return list(storage['storage'].values())
return list(storage["storage"].values())
def set_watchlist(watchlist: List[str]) -> None:
client.update_storage({'storage': dict(enumerate(watchlist))})
client.update_storage({"storage": dict(enumerate(watchlist))})
def handle_event(event: Dict[str, Any]) -> None:
try:
if event['type'] == 'realm_user' and event['op'] == 'add':
if event["type"] == "realm_user" and event["op"] == "add":
watchlist = get_watchlist()
watchlist.append(event['person']['email'])
watchlist.append(event["person"]["email"])
set_watchlist(watchlist)
return
if event['type'] == 'message':
stream = event['message']['display_recipient']
if event["type"] == "message":
stream = event["message"]["display_recipient"]
if stream not in streams_to_watch and stream not in streams_to_cancel:
return
watchlist = get_watchlist()
if event['message']['sender_email'] in watchlist:
watchlist.remove(event['message']['sender_email'])
if event["message"]["sender_email"] in watchlist:
watchlist.remove(event["message"]["sender_email"])
if stream not in streams_to_cancel:
client.send_message(
{
'type': 'private',
'to': event['message']['sender_email'],
'content': welcome_text.format(event['message']['sender_short_name']),
"type": "private",
"to": event["message"]["sender_email"],
"content": welcome_text.format(event["message"]["sender_short_name"]),
}
)
set_watchlist(watchlist)
@ -92,7 +92,7 @@ def handle_event(event: Dict[str, Any]) -> None:
def start_event_handler() -> None:
print("Starting event handler...")
client.call_on_each_event(handle_event, event_types=['realm_user', 'message'])
client.call_on_each_event(handle_event, event_types=["realm_user", "message"])
client = zulip.Client()

View file

@ -10,25 +10,25 @@ import zulip
logging.basicConfig()
log = logging.getLogger('zulip-send')
log = logging.getLogger("zulip-send")
def do_send_message(client: zulip.Client, message_data: Dict[str, Any]) -> bool:
'''Sends a message and optionally prints status about the same.'''
"""Sends a message and optionally prints status about the same."""
if message_data['type'] == 'stream':
if message_data["type"] == "stream":
log.info(
'Sending message to stream "%s", subject "%s"... '
% (message_data['to'], message_data['subject'])
% (message_data["to"], message_data["subject"])
)
else:
log.info('Sending message to %s... ' % (message_data['to'],))
log.info("Sending message to %s... " % (message_data["to"],))
response = client.send_message(message_data)
if response['result'] == 'success':
log.info('Message sent.')
if response["result"] == "success":
log.info("Message sent.")
return True
else:
log.error(response['msg'])
log.error(response["msg"])
return False
@ -46,27 +46,27 @@ def main() -> int:
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
parser.add_argument(
'recipients', nargs='*', help='email addresses of the recipients of the message'
"recipients", nargs="*", help="email addresses of the recipients of the message"
)
parser.add_argument(
'-m', '--message', help='Specifies the message to send, prevents interactive prompting.'
"-m", "--message", help="Specifies the message to send, prevents interactive prompting."
)
group = parser.add_argument_group('Stream parameters')
group = parser.add_argument_group("Stream parameters")
group.add_argument(
'-s',
'--stream',
dest='stream',
action='store',
help='Allows the user to specify a stream for the message.',
"-s",
"--stream",
dest="stream",
action="store",
help="Allows the user to specify a stream for the message.",
)
group.add_argument(
'-S',
'--subject',
dest='subject',
action='store',
help='Allows the user to specify a subject for the message.',
"-S",
"--subject",
dest="subject",
action="store",
help="Allows the user to specify a subject for the message.",
)
options = parser.parse_args()
@ -75,11 +75,11 @@ def main() -> int:
logging.getLogger().setLevel(logging.INFO)
# Sanity check user data
if len(options.recipients) != 0 and (options.stream or options.subject):
parser.error('You cannot specify both a username and a stream/subject.')
parser.error("You cannot specify both a username and a stream/subject.")
if len(options.recipients) == 0 and (bool(options.stream) != bool(options.subject)):
parser.error('Stream messages must have a subject')
parser.error("Stream messages must have a subject")
if len(options.recipients) == 0 and not (options.stream and options.subject):
parser.error('You must specify a stream/subject or at least one recipient.')
parser.error("You must specify a stream/subject or at least one recipient.")
client = zulip.init_from_options(options)
@ -88,16 +88,16 @@ def main() -> int:
if options.stream:
message_data = {
'type': 'stream',
'content': options.message,
'subject': options.subject,
'to': options.stream,
"type": "stream",
"content": options.message,
"subject": options.subject,
"to": options.stream,
}
else:
message_data = {
'type': 'private',
'content': options.message,
'to': options.recipients,
"type": "private",
"content": options.message,
"to": options.recipients,
}
if not do_send_message(client, message_data):
@ -105,5 +105,5 @@ def main() -> int:
return 0
if __name__ == '__main__':
if __name__ == "__main__":
sys.exit(main())