aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--_pytest/conftest.py58
-rw-r--r--_pytest/test_command_reply.py17
-rw-r--r--_pytest/test_eventrouter.py4
-rw-r--r--_pytest/test_everything.py2
-rw-r--r--_pytest/test_formatted_name.py387
-rw-r--r--_pytest/test_formatting.py34
-rw-r--r--_pytest/test_linkifytext.py91
-rw-r--r--_pytest/test_presencechange.py24
-rw-r--r--_pytest/test_process_message.py64
-rw-r--r--_pytest/test_processreply.py12
-rw-r--r--_pytest/test_processsubteamcreated.py4
-rw-r--r--_pytest/test_processsubteamupdated.py12
-rw-r--r--_pytest/test_processteamjoin.py6
-rw-r--r--_pytest/test_sendmessage.py12
-rw-r--r--_pytest/test_thread.py26
-rw-r--r--_pytest/test_topic_command.py52
-rw-r--r--_pytest/test_unfurl.py325
-rw-r--r--_pytest/test_unwrap_attachments.py779
-rw-r--r--_pytest/test_utf8_helpers.py43
-rwxr-xr-xgenerate_docs.py44
-rwxr-xr-xgenerate_weemoji.py10
-rw-r--r--wee_slack.py3016
22 files changed, 3154 insertions, 1868 deletions
diff --git a/_pytest/conftest.py b/_pytest/conftest.py
index 1ad2310..b0eb082 100644
--- a/_pytest/conftest.py
+++ b/_pytest/conftest.py
@@ -14,119 +14,153 @@ sys.path.append(".")
import wee_slack
from wee_slack import EventRouter, SlackRequest, initiate_connection
+
class fakewebsocket(object):
def __init__(self):
self.returndata = []
self.sentdata = []
+
def add(self, data):
- self.returndata.append(json.dumps(data).encode('utf-8'))
+ self.returndata.append(json.dumps(data).encode("utf-8"))
+
def recv(self):
- return self.recv_data()[1].decode('utf-8')
+ return self.recv_data()[1].decode("utf-8")
+
def recv_data(self, control_frame=False):
if self.returndata:
return ABNF.OPCODE_TEXT, self.returndata.pop(0)
else:
raise ssl.SSLWantReadError()
+
def send(self, data):
self.sentdata.append(data)
+
@pytest.fixture
def mock_websocket():
return fakewebsocket()
+
@pytest.fixture
def realish_eventrouter(mock_websocket, mock_weechat):
e = EventRouter()
wee_slack.EVENTROUTER = e
- context = e.store_context(initiate_connection('xoxs-token'))
- with open('_pytest/data/http/rtm.start.json') as rtmstartfile:
+ context = e.store_context(initiate_connection("xoxs-token"))
+ with open("_pytest/data/http/rtm.start.json") as rtmstartfile:
if sys.version_info.major == 2:
- rtmstartdata = rtmstartfile.read().decode('utf-8')
+ rtmstartdata = rtmstartfile.read().decode("utf-8")
else:
rtmstartdata = rtmstartfile.read()
- e.receive_httprequest_callback(context, '', 0, rtmstartdata, '')
+ e.receive_httprequest_callback(context, "", 0, rtmstartdata, "")
while len(e.queue):
e.handle_next()
for team in e.teams.values():
team.ws = mock_websocket
return e
+
@pytest.fixture
def team(realish_eventrouter):
return next(iter(realish_eventrouter.teams.values()))
+
@pytest.fixture
def channel_general(team):
- return team.channels[team.get_channel_map()['#general']]
+ return team.channels[team.get_channel_map()["#general"]]
+
@pytest.fixture
def channel_private(team):
- return team.channels[team.get_channel_map()['&some-private-channel']]
+ return team.channels[team.get_channel_map()["&some-private-channel"]]
+
@pytest.fixture
def channel_dm(team):
- return team.channels[team.get_channel_map()['alice']]
+ return team.channels[team.get_channel_map()["alice"]]
+
@pytest.fixture
def channel_mpdm(team):
- return team.channels[team.get_channel_map()['CharlesTestuser,alice']]
+ return team.channels[team.get_channel_map()["CharlesTestuser,alice"]]
+
@pytest.fixture
def user_alice(team):
- return team.users[team.get_username_map()['alice']]
+ return team.users[team.get_username_map()["alice"]]
-class FakeWeechat():
+
+class FakeWeechat:
"""
this is the thing that acts as "w." everywhere..
basically mock out all of the weechat calls here i guess
"""
+
WEECHAT_RC_ERROR = 0
WEECHAT_RC_OK = 1
WEECHAT_RC_OK_EAT = 2
+
def __init__(self):
self.config = {}
+
def prnt(*args):
output = "("
for arg in args:
if arg != None:
output += "{}, ".format(arg)
print("w.prnt {}".format(output))
+
def hdata_get(*args):
return "0x000001"
+
def hdata_integer(*args):
return 1
+
def hdata_pointer(*args):
return "0x000002"
+
def hdata_time(*args):
return "1355517519"
+
def hdata_string(*args):
return "testuser"
+
def buffer_new(*args):
return "0x" + "".join(random.choice(string.digits) for _ in range(8))
+
def prefix(self, type):
return ""
+
def config_get_plugin(self, key):
return self.config.get(key, "")
+
def config_get(self, key):
return ""
+
def config_integer(self, key):
return 1000
+
def config_set_plugin(self, key, value):
self.config[key] = value
+
def config_string(self, key):
return ""
+
def color(self, name):
return "<[color {}]>".format(name)
+
def info_get(self, info_name, arguments):
if info_name == "color_rgb2term":
return arguments
else:
return ""
+
def __getattr__(self, name):
def method(*args):
pass
+
return method
+
@pytest.fixture
def mock_weechat():
wee_slack.w = FakeWeechat()
diff --git a/_pytest/test_command_reply.py b/_pytest/test_command_reply.py
index a674d86..f78e0c7 100644
--- a/_pytest/test_command_reply.py
+++ b/_pytest/test_command_reply.py
@@ -4,13 +4,16 @@ import json
from wee_slack import SlackTS, command_reply
-parent_ts = SlackTS('1485975824.000004')
-child_ts = SlackTS('1485975835.000005')
+parent_ts = SlackTS("1485975824.000004")
+child_ts = SlackTS("1485975835.000005")
-def test_replying_to_child_should_use_parent_ts(realish_eventrouter, team, channel_general):
+
+def test_replying_to_child_should_use_parent_ts(
+ realish_eventrouter, team, channel_general
+):
datafiles = [
- '_pytest/data/websocket/1485975824.48-message.json',
- '_pytest/data/websocket/1485975836.23-message.json'
+ "_pytest/data/websocket/1485975824.48-message.json",
+ "_pytest/data/websocket/1485975836.23-message.json",
]
for datafile in datafiles:
data = json.loads(open(datafile).read())
@@ -19,7 +22,7 @@ def test_replying_to_child_should_use_parent_ts(realish_eventrouter, team, chann
realish_eventrouter.handle_next()
child_hash = channel_general.hashed_messages[child_ts]
- command_reply(None, channel_general.channel_buffer, '${} test'.format(child_hash))
+ command_reply(None, channel_general.channel_buffer, "${} test".format(child_hash))
sent = json.loads(team.ws.sentdata[0])
- assert sent['thread_ts'] == parent_ts
+ assert sent["thread_ts"] == parent_ts
diff --git a/_pytest/test_eventrouter.py b/_pytest/test_eventrouter.py
index de267c1..5420d5a 100644
--- a/_pytest/test_eventrouter.py
+++ b/_pytest/test_eventrouter.py
@@ -13,7 +13,7 @@ def test_EventRouter(mock_weechat):
# Handling an event removes from the queue.
e = EventRouter()
# Create a function to test we are called
- e.proc['testfunc'] = lambda json, eventrouter, team, channel, metadata: json
+ e.proc["testfunc"] = lambda json, eventrouter, team, channel, metadata: json
e.receive({"type": "testfunc"})
e.handle_next()
assert len(e.queue) == 0
@@ -21,7 +21,7 @@ def test_EventRouter(mock_weechat):
# Handling a local event removes from the queue.
e = EventRouter()
# Create a function to test we are called
- e.proc['local_testfunc'] = lambda json, eventrouter, team, channel, metadata: json
+ e.proc["local_testfunc"] = lambda json, eventrouter, team, channel, metadata: json
e.receive({"type": "local_testfunc"})
e.handle_next()
assert len(e.queue) == 0
diff --git a/_pytest/test_everything.py b/_pytest/test_everything.py
index ed045ae..282c89e 100644
--- a/_pytest/test_everything.py
+++ b/_pytest/test_everything.py
@@ -8,7 +8,7 @@ def test_everything(realish_eventrouter, team):
datafiles = glob.glob("_pytest/data/websocket/*.json")
for fname in sorted(datafiles):
- data = json.loads(open(fname, 'r').read())
+ data = json.loads(open(fname, "r").read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
diff --git a/_pytest/test_formatted_name.py b/_pytest/test_formatted_name.py
index 5383b63..0dd2ee3 100644
--- a/_pytest/test_formatted_name.py
+++ b/_pytest/test_formatted_name.py
@@ -4,198 +4,205 @@ import pytest
import wee_slack
-@pytest.mark.parametrize('case', (
- {
- "type": "channel",
- "style": "default",
- "typing": False,
- "present": False,
- "name": "#general"
- },
- {
- "type": "channel",
- "style": "default",
- "typing": True,
- "present": True,
- "name": "#general"
- },
- {
- "type": "channel",
- "style": "long_default",
- "typing": False,
- "present": False,
- "name": "slack.weeslacktest.#general"
- },
- {
- "type": "channel",
- "style": "long_default",
- "typing": True,
- "present": True,
- "name": "slack.weeslacktest.#general"
- },
- {
- "type": "channel",
- "style": "sidebar",
- "typing": False,
- "present": False,
- "name": "#general"
- },
- {
- "type": "channel",
- "style": "sidebar",
- "typing": True,
- "present": True,
- "name": ">general"
- },
- {
- "type": "private",
- "style": "default",
- "typing": False,
- "present": False,
- "name": "&some-private-channel"
- },
- {
- "type": "private",
- "style": "default",
- "typing": True,
- "present": True,
- "name": "&some-private-channel"
- },
- {
- "type": "private",
- "style": "long_default",
- "typing": False,
- "present": False,
- "name": "slack.weeslacktest.&some-private-channel"
- },
- {
- "type": "private",
- "style": "long_default",
- "typing": True,
- "present": True,
- "name": "slack.weeslacktest.&some-private-channel"
- },
- {
- "type": "private",
- "style": "sidebar",
- "typing": False,
- "present": False,
- "name": "&some-private-channel"
- },
- {
- "type": "private",
- "style": "sidebar",
- "typing": True,
- "present": True,
- "name": ">some-private-channel"
- },
- {
- "type": "dm",
- "style": "default",
- "typing": False,
- "present": False,
- "name": "alice"
- },
- {
- "type": "dm",
- "style": "default",
- "typing": True,
- "present": True,
- "name": "alice"
- },
- {
- "type": "dm",
- "style": "long_default",
- "typing": False,
- "present": False,
- "name": "slack.weeslacktest.alice"
- },
- {
- "type": "dm",
- "style": "long_default",
- "typing": True,
- "present": True,
- "name": "slack.weeslacktest.alice"
- },
- {
- "type": "dm",
- "style": "sidebar",
- "typing": False,
- "present": False,
- "name": " alice"
- },
- {
- "type": "dm",
- "style": "sidebar",
- "typing": False,
- "present": True,
- "name": "+alice"
- },
- {
- "type": "dm",
- "style": "sidebar",
- "typing": True,
- "present": False,
- "name": ">alice"
- },
- {
- "type": "dm",
- "style": "sidebar",
- "typing": True,
- "present": True,
- "name": ">alice"
- },
- {
- "type": "mpdm",
- "style": "default",
- "typing": False,
- "present": False,
- "name": "CharlesTestuser,alice"
- },
- {
- "type": "mpdm",
- "style": "default",
- "typing": True,
- "present": True,
- "name": "CharlesTestuser,alice"
- },
- {
- "type": "mpdm",
- "style": "long_default",
- "typing": False,
- "present": False,
- "name": "slack.weeslacktest.CharlesTestuser,alice"
- },
- {
- "type": "mpdm",
- "style": "long_default",
- "typing": True,
- "present": True,
- "name": "slack.weeslacktest.CharlesTestuser,alice"
- },
- {
- "type": "mpdm",
- "style": "sidebar",
- "typing": False,
- "present": False,
- "name": "@CharlesTestuser,alice"
- },
- {
- "type": "mpdm",
- "style": "sidebar",
- "typing": True,
- "present": True,
- "name": ">CharlesTestuser,alice"
- },
-))
-def test_formatted_name(case, channel_general, channel_private, channel_dm, channel_mpdm):
+@pytest.mark.parametrize(
+ "case",
+ (
+ {
+ "type": "channel",
+ "style": "default",
+ "typing": False,
+ "present": False,
+ "name": "#general",
+ },
+ {
+ "type": "channel",
+ "style": "default",
+ "typing": True,
+ "present": True,
+ "name": "#general",
+ },
+ {
+ "type": "channel",
+ "style": "long_default",
+ "typing": False,
+ "present": False,
+ "name": "slack.weeslacktest.#general",
+ },
+ {
+ "type": "channel",
+ "style": "long_default",
+ "typing": True,
+ "present": True,
+ "name": "slack.weeslacktest.#general",
+ },
+ {
+ "type": "channel",
+ "style": "sidebar",
+ "typing": False,
+ "present": False,
+ "name": "#general",
+ },
+ {
+ "type": "channel",
+ "style": "sidebar",
+ "typing": True,
+ "present": True,
+ "name": ">general",
+ },
+ {
+ "type": "private",
+ "style": "default",
+ "typing": False,
+ "present": False,
+ "name": "&some-private-channel",
+ },
+ {
+ "type": "private",
+ "style": "default",
+ "typing": True,
+ "present": True,
+ "name": "&some-private-channel",
+ },
+ {
+ "type": "private",
+ "style": "long_default",
+ "typing": False,
+ "present": False,
+ "name": "slack.weeslacktest.&some-private-channel",
+ },
+ {
+ "type": "private",
+ "style": "long_default",
+ "typing": True,
+ "present": True,
+ "name": "slack.weeslacktest.&some-private-channel",
+ },
+ {
+ "type": "private",
+ "style": "sidebar",
+ "typing": False,
+ "present": False,
+ "name": "&some-private-channel",
+ },
+ {
+ "type": "private",
+ "style": "sidebar",
+ "typing": True,
+ "present": True,
+ "name": ">some-private-channel",
+ },
+ {
+ "type": "dm",
+ "style": "default",
+ "typing": False,
+ "present": False,
+ "name": "alice",
+ },
+ {
+ "type": "dm",
+ "style": "default",
+ "typing": True,
+ "present": True,
+ "name": "alice",
+ },
+ {
+ "type": "dm",
+ "style": "long_default",
+ "typing": False,
+ "present": False,
+ "name": "slack.weeslacktest.alice",
+ },
+ {
+ "type": "dm",
+ "style": "long_default",
+ "typing": True,
+ "present": True,
+ "name": "slack.weeslacktest.alice",
+ },
+ {
+ "type": "dm",
+ "style": "sidebar",
+ "typing": False,
+ "present": False,
+ "name": " alice",
+ },
+ {
+ "type": "dm",
+ "style": "sidebar",
+ "typing": False,
+ "present": True,
+ "name": "+alice",
+ },
+ {
+ "type": "dm",
+ "style": "sidebar",
+ "typing": True,
+ "present": False,
+ "name": ">alice",
+ },
+ {
+ "type": "dm",
+ "style": "sidebar",
+ "typing": True,
+ "present": True,
+ "name": ">alice",
+ },
+ {
+ "type": "mpdm",
+ "style": "default",
+ "typing": False,
+ "present": False,
+ "name": "CharlesTestuser,alice",
+ },
+ {
+ "type": "mpdm",
+ "style": "default",
+ "typing": True,
+ "present": True,
+ "name": "CharlesTestuser,alice",
+ },
+ {
+ "type": "mpdm",
+ "style": "long_default",
+ "typing": False,
+ "present": False,
+ "name": "slack.weeslacktest.CharlesTestuser,alice",
+ },
+ {
+ "type": "mpdm",
+ "style": "long_default",
+ "typing": True,
+ "present": True,
+ "name": "slack.weeslacktest.CharlesTestuser,alice",
+ },
+ {
+ "type": "mpdm",
+ "style": "sidebar",
+ "typing": False,
+ "present": False,
+ "name": "@CharlesTestuser,alice",
+ },
+ {
+ "type": "mpdm",
+ "style": "sidebar",
+ "typing": True,
+ "present": True,
+ "name": ">CharlesTestuser,alice",
+ },
+ ),
+)
+def test_formatted_name(
+ case, channel_general, channel_private, channel_dm, channel_mpdm
+):
wee_slack.config.channel_name_typing_indicator = True
wee_slack.config.show_buflist_presence = True
channels = {
- "channel": channel_general,
- "private": channel_private,
- "dm": channel_dm,
- "mpdm": channel_mpdm,
+ "channel": channel_general,
+ "private": channel_private,
+ "dm": channel_dm,
+ "mpdm": channel_mpdm,
}
- name = channels[case["type"]].formatted_name(case["style"], case["typing"], case["present"])
+ name = channels[case["type"]].formatted_name(
+ case["style"], case["typing"], case["present"]
+ )
assert name == case["name"]
diff --git a/_pytest/test_formatting.py b/_pytest/test_formatting.py
index 4f6daa2..e88c4af 100644
--- a/_pytest/test_formatting.py
+++ b/_pytest/test_formatting.py
@@ -6,28 +6,34 @@ import re
import wee_slack
-@pytest.mark.parametrize("text", [
- """
+@pytest.mark.parametrize(
+ "text",
+ [
+ """
* an item
* another item
""",
- "* Run this command: `find . -name '*.exe'`",
-])
+ "* Run this command: `find . -name '*.exe'`",
+ ],
+)
def test_does_not_format(realish_eventrouter, text):
assert wee_slack.render_formatting(text) == text
-@pytest.mark.parametrize("text", [
- "`hello *bar*`",
- "`*`",
- "`* *`",
- "`* * *`",
- "`* * * *`",
- "`* * * * *`",
- "`* * * * * *`",
-])
+@pytest.mark.parametrize(
+ "text",
+ [
+ "`hello *bar*`",
+ "`*`",
+ "`* *`",
+ "`* * *`",
+ "`* * * *`",
+ "`* * * * *`",
+ "`* * * * * *`",
+ ],
+)
def test_preserves_format_chars_in_code(realish_eventrouter, text):
formatted_text = wee_slack.render_formatting(text)
# TODO: wee-slack erroneously inserts formatting in code blocks
- formatted_text = re.sub(r'<\[color .*?\]>', '', formatted_text)
+ formatted_text = re.sub(r"<\[color .*?\]>", "", formatted_text)
assert formatted_text == text
diff --git a/_pytest/test_linkifytext.py b/_pytest/test_linkifytext.py
index 4f9cd3b..60bf923 100644
--- a/_pytest/test_linkifytext.py
+++ b/_pytest/test_linkifytext.py
@@ -8,86 +8,103 @@ from wee_slack import linkify_text
def test_linkifytext_does_partial_html_entity_encoding(team):
- text = linkify_text('& < > \' "', team)
+ text = linkify_text("& < > ' \"", team)
+
+ assert text == "&amp; &lt; &gt; ' \""
- assert text == '&amp; &lt; &gt; \' "'
def test_linkifytext_names_with_paranthesis(team):
- text = linkify_text('@JohnDoe(jdoe): my test message', team)
+ text = linkify_text("@JohnDoe(jdoe): my test message", team)
+
+ assert text == "@JohnDoe(jdoe): my test message"
- assert text == '@JohnDoe(jdoe): my test message'
def test_linkifytext_names_with_accents(team):
- text = linkify_text('@ÁrvíztűrőTükörfúrógép(atukorfurogep): my test message', team)
+ text = linkify_text("@ÁrvíztűrőTükörfúrógép(atukorfurogep): my test message", team)
+
+ assert text == "@ÁrvíztűrőTükörfúrógép(atukorfurogep): my test message"
- assert text == '@ÁrvíztűrőTükörfúrógép(atukorfurogep): my test message'
def test_linkifytext_formatting_characters(team):
- text = linkify_text('\x02\x1Dmy test message\x1D\x02', team)
+ text = linkify_text("\x02\x1Dmy test message\x1D\x02", team)
+
+ assert text == "*_my test message_*"
- assert text == '*_my test message_*'
def test_linkifytext_with_many_paranthesis(team):
- text = linkify_text('@k(o(v)a)())s: my(( test) message', team)
+ text = linkify_text("@k(o(v)a)())s: my(( test) message", team)
+
+ assert text == "@k(o(v)a)())s: my(( test) message"
- assert text == '@k(o(v)a)())s: my(( test) message'
def test_linkifytext_names_with_apostrophe(team):
- text = linkify_text('@O\'Connor: my test message', team)
+ text = linkify_text("@O'Connor: my test message", team)
+
+ assert text == "@O'Connor: my test message"
- assert text == '@O\'Connor: my test message'
def test_linkifytext_names_with_subgroup_notification(team):
- subteam = team.subteams['TGX0ALBK3']
- message = 'This is a message for a subteam'
- text = linkify_text('{}: {}'.format(subteam.handle, message), team)
+ subteam = team.subteams["TGX0ALBK3"]
+ message = "This is a message for a subteam"
+ text = linkify_text("{}: {}".format(subteam.handle, message), team)
+
+ assert text == "<!subteam^{}|{}>: {}".format(
+ subteam.identifier, subteam.handle, message
+ )
- assert text == '<!subteam^{}|{}>: {}'.format(subteam.identifier, subteam.handle, message)
def test_linkifytext_at_channel(team):
- text = linkify_text('@channel: my test message', team)
+ text = linkify_text("@channel: my test message", team)
+
+ assert text == "<!channel>: my test message"
- assert text == '<!channel>: my test message'
def test_linkifytext_at_everyone(team):
- text = linkify_text('@everyone: my test message', team)
+ text = linkify_text("@everyone: my test message", team)
+
+ assert text == "<!everyone>: my test message"
- assert text == '<!everyone>: my test message'
def test_linkifytext_at_group(team):
- text = linkify_text('@group: my test message', team)
+ text = linkify_text("@group: my test message", team)
+
+ assert text == "<!group>: my test message"
- assert text == '<!group>: my test message'
def test_linkifytext_at_here(team):
- text = linkify_text('@here: my test message', team)
+ text = linkify_text("@here: my test message", team)
+
+ assert text == "<!here>: my test message"
- assert text == '<!here>: my test message'
def test_linkifytext_channel(team, channel_general):
- channel_name = re.sub(r'^[#&]', '', channel_general.name)
- text = linkify_text('#{}: my test message'.format(channel_name), team)
+ channel_name = re.sub(r"^[#&]", "", channel_general.name)
+ text = linkify_text("#{}: my test message".format(channel_name), team)
+
+ assert text == "<#{}|{}>: my test message".format(channel_general.id, channel_name)
- assert text == '<#{}|{}>: my test message'.format(channel_general.id, channel_name)
def test_linkifytext_not_private_using_hash(team, channel_private):
- channel_name = re.sub(r'^[#&]', '', channel_private.name)
- text = linkify_text('#{}: my test message'.format(channel_name), team)
+ channel_name = re.sub(r"^[#&]", "", channel_private.name)
+ text = linkify_text("#{}: my test message".format(channel_name), team)
+
+ assert text == "#{}: my test message".format(channel_name)
- assert text == '#{}: my test message'.format(channel_name)
def test_linkifytext_not_private_using_ampersand(team, channel_private):
- channel_name = re.sub(r'^[#&]', '', channel_private.name)
- text = linkify_text('&{}: my test message'.format(channel_name), team)
+ channel_name = re.sub(r"^[#&]", "", channel_private.name)
+ text = linkify_text("&{}: my test message".format(channel_name), team)
+
+ assert text == "&amp;{}: my test message".format(channel_name)
- assert text == '&amp;{}: my test message'.format(channel_name)
def test_linkifytext_not_dm(team, channel_dm):
- text = linkify_text('#{}: my test message'.format(channel_dm.name), team)
+ text = linkify_text("#{}: my test message".format(channel_dm.name), team)
+
+ assert text == "#{}: my test message".format(channel_dm.name)
- assert text == '#{}: my test message'.format(channel_dm.name)
def test_linkifytext_not_mpdm(team, channel_mpdm):
- text = linkify_text('#{}: my test message'.format(channel_mpdm.name), team)
+ text = linkify_text("#{}: my test message".format(channel_mpdm.name), team)
- assert text == '#{}: my test message'.format(channel_mpdm.name)
+ assert text == "#{}: my test message".format(channel_mpdm.name)
diff --git a/_pytest/test_presencechange.py b/_pytest/test_presencechange.py
index ffe28c9..fc4d379 100644
--- a/_pytest/test_presencechange.py
+++ b/_pytest/test_presencechange.py
@@ -2,16 +2,20 @@ from __future__ import print_function, unicode_literals
def test_PresenceChange(realish_eventrouter, team, user_alice):
- team.ws.add({
- "type": "presence_change",
- "user": user_alice.identifier,
- "presence": "active",
- })
- team.ws.add({
- "type": "presence_change",
- "user": user_alice.identifier,
- "presence": "away",
- })
+ team.ws.add(
+ {
+ "type": "presence_change",
+ "user": user_alice.identifier,
+ "presence": "active",
+ }
+ )
+ team.ws.add(
+ {
+ "type": "presence_change",
+ "user": user_alice.identifier,
+ "presence": "away",
+ }
+ )
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
diff --git a/_pytest/test_process_message.py b/_pytest/test_process_message.py
index b6d8ab6..5017c10 100644
--- a/_pytest/test_process_message.py
+++ b/_pytest/test_process_message.py
@@ -7,15 +7,33 @@ from wee_slack import SlackTS
def test_process_message(realish_eventrouter, team, user_alice):
messages = []
- messages.append(json.loads(open('_pytest/data/websocket/1485975421.33-message.json', 'r').read()))
+ messages.append(
+ json.loads(
+ open("_pytest/data/websocket/1485975421.33-message.json", "r").read()
+ )
+ )
# test message and then change
- messages.append(json.loads(open('_pytest/data/websocket/1485976151.6-message.json', 'r').read()))
- messages.append(json.loads(open('_pytest/data/websocket/1485976157.18-message.json', 'r').read()))
+ messages.append(
+ json.loads(open("_pytest/data/websocket/1485976151.6-message.json", "r").read())
+ )
+ messages.append(
+ json.loads(
+ open("_pytest/data/websocket/1485976157.18-message.json", "r").read()
+ )
+ )
# test message then deletion
- messages.append(json.loads(open('_pytest/data/websocket/1485975698.45-message.json', 'r').read()))
- messages.append(json.loads(open('_pytest/data/websocket/1485975723.85-message.json', 'r').read()))
+ messages.append(
+ json.loads(
+ open("_pytest/data/websocket/1485975698.45-message.json", "r").read()
+ )
+ )
+ messages.append(
+ json.loads(
+ open("_pytest/data/websocket/1485975723.85-message.json", "r").read()
+ )
+ )
for m in messages:
m["user"] = user_alice.id
@@ -30,20 +48,32 @@ def test_process_message(realish_eventrouter, team, user_alice):
assert sum([len(channel.messages) for channel in team.channels.values()]) == 3
- unchanged_message_channel = team.channels['D3ZEQULHZ']
- unchanged_message_ts = SlackTS('1485975421.000002')
+ unchanged_message_channel = team.channels["D3ZEQULHZ"]
+ unchanged_message_ts = SlackTS("1485975421.000002")
assert list(unchanged_message_channel.messages.keys()) == [unchanged_message_ts]
- assert unchanged_message_channel.messages[unchanged_message_ts].message_json['text'] == 'hi bob'
- assert 'edited' not in unchanged_message_channel.messages[unchanged_message_ts].message_json
+ assert (
+ unchanged_message_channel.messages[unchanged_message_ts].message_json["text"]
+ == "hi bob"
+ )
+ assert (
+ "edited"
+ not in unchanged_message_channel.messages[unchanged_message_ts].message_json
+ )
- changed_message_channel = team.channels['C407ABS94']
- changed_message_ts = SlackTS('1485976151.000016')
+ changed_message_channel = team.channels["C407ABS94"]
+ changed_message_ts = SlackTS("1485976151.000016")
assert list(changed_message_channel.messages.keys()) == [changed_message_ts]
- assert changed_message_channel.messages[changed_message_ts].message_json['text'] == 'referencing a <#C407ABS94|general>'
- assert 'edited' in changed_message_channel.messages[changed_message_ts].message_json
+ assert (
+ changed_message_channel.messages[changed_message_ts].message_json["text"]
+ == "referencing a <#C407ABS94|general>"
+ )
+ assert "edited" in changed_message_channel.messages[changed_message_ts].message_json
- deleted_message_channel = team.channels['G3ZGMF4RZ']
- deleted_message_ts = SlackTS('1485975698.000002')
+ deleted_message_channel = team.channels["G3ZGMF4RZ"]
+ deleted_message_ts = SlackTS("1485975698.000002")
assert list(deleted_message_channel.messages.keys()) == [deleted_message_ts]
- deleted_str = '<[color red]>(deleted)<[color reset]>'
- assert deleted_message_channel.messages[deleted_message_ts].message_json['text'] == deleted_str
+ deleted_str = "<[color red]>(deleted)<[color reset]>"
+ assert (
+ deleted_message_channel.messages[deleted_message_ts].message_json["text"]
+ == deleted_str
+ )
diff --git a/_pytest/test_processreply.py b/_pytest/test_processreply.py
index 994b43f..34c2623 100644
--- a/_pytest/test_processreply.py
+++ b/_pytest/test_processreply.py
@@ -4,14 +4,16 @@ from wee_slack import SlackTS
def test_process_reply(realish_eventrouter, team, channel_general):
- message_ts = SlackTS('12341234.123456')
- message_text = 'reply test'
+ message_ts = SlackTS("12341234.123456")
+ message_text = "reply test"
channel_general.send_message(message_text)
- team.ws.add({'ok': True, 'reply_to': 1, '_team': team.team_hash, 'ts': str(message_ts)})
+ team.ws.add(
+ {"ok": True, "reply_to": 1, "_team": team.team_hash, "ts": str(message_ts)}
+ )
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
assert message_ts in channel_general.messages
message_json = channel_general.messages[message_ts].message_json
- assert message_json['ts'] == message_ts
- assert message_json['text'] == message_text
+ assert message_json["ts"] == message_ts
+ assert message_json["text"] == message_text
diff --git a/_pytest/test_processsubteamcreated.py b/_pytest/test_processsubteamcreated.py
index 299ac6f..9ff3ee2 100644
--- a/_pytest/test_processsubteamcreated.py
+++ b/_pytest/test_processsubteamcreated.py
@@ -6,8 +6,8 @@ import json
def test_process_subteam_created(realish_eventrouter, team):
assert len(team.subteams) == 1
- datafile = '_pytest/data/websocket/1483975206.59-subteam_created.json'
- data = json.loads(open(datafile, 'r').read())
+ datafile = "_pytest/data/websocket/1483975206.59-subteam_created.json"
+ data = json.loads(open(datafile, "r").read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
diff --git a/_pytest/test_processsubteamupdated.py b/_pytest/test_processsubteamupdated.py
index e3eb824..6eea30f 100644
--- a/_pytest/test_processsubteamupdated.py
+++ b/_pytest/test_processsubteamupdated.py
@@ -6,13 +6,13 @@ import json
def test_process_subteam_self_updated(realish_eventrouter, team):
assert len(team.subteams) == 1
- datafile = '_pytest/data/websocket/1483975206.59-subteam_updated.json'
- data = json.loads(open(datafile, 'r').read())
+ datafile = "_pytest/data/websocket/1483975206.59-subteam_updated.json"
+ data = json.loads(open(datafile, "r").read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
- subteam = team.subteams['TGX0ALBK3']
+ subteam = team.subteams["TGX0ALBK3"]
- assert '@{}'.format(data['subteam']['handle']) == subteam.handle
- assert data['subteam']['description'] == subteam.description
- assert data['subteam']['name'] == subteam.name
+ assert "@{}".format(data["subteam"]["handle"]) == subteam.handle
+ assert data["subteam"]["description"] == subteam.description
+ assert data["subteam"]["name"] == subteam.name
diff --git a/_pytest/test_processteamjoin.py b/_pytest/test_processteamjoin.py
index f965bbb..e07ee0a 100644
--- a/_pytest/test_processteamjoin.py
+++ b/_pytest/test_processteamjoin.py
@@ -5,12 +5,12 @@ import json
def test_process_team_join(realish_eventrouter, team):
# delete charles so we can add him
- del team.users['U4096CBHC']
+ del team.users["U4096CBHC"]
assert len(team.users) == 3
- datafile = '_pytest/data/websocket/1485975606.59-team_join.json'
- data = json.loads(open(datafile, 'r').read())
+ datafile = "_pytest/data/websocket/1485975606.59-team_join.json"
+ data = json.loads(open(datafile, "r").read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
diff --git a/_pytest/test_sendmessage.py b/_pytest/test_sendmessage.py
index 17f38d7..eb205c1 100644
--- a/_pytest/test_sendmessage.py
+++ b/_pytest/test_sendmessage.py
@@ -4,15 +4,15 @@ import json
def test_send_message(realish_eventrouter, team, channel_general):
- message_text = 'send message test'
+ message_text = "send message test"
channel_general.send_message(message_text)
sent = json.loads(team.ws.sentdata[0])
assert sent == {
- 'text': message_text,
- 'type': 'message',
- 'user': team.myidentifier,
- 'channel': channel_general.id,
- 'id': 1,
+ "text": message_text,
+ "type": "message",
+ "user": team.myidentifier,
+ "channel": channel_general.id,
+ "id": 1,
}
diff --git a/_pytest/test_thread.py b/_pytest/test_thread.py
index 4095e77..06150a3 100644
--- a/_pytest/test_thread.py
+++ b/_pytest/test_thread.py
@@ -5,33 +5,39 @@ import json
from wee_slack import SlackTS
-thread_ts = SlackTS('1485975824.000004')
+thread_ts = SlackTS("1485975824.000004")
def test_message_has_thread_suffix(realish_eventrouter, team, channel_general):
- datafile = '_pytest/data/websocket/1485975824.48-message.json'
+ datafile = "_pytest/data/websocket/1485975824.48-message.json"
data = json.loads(open(datafile).read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
- message_text = channel_general.messages[thread_ts].message_json['_rendered_text']
- assert message_text == 'generally, yep!'
+ message_text = channel_general.messages[thread_ts].message_json["_rendered_text"]
+ assert message_text == "generally, yep!"
- datafile = '_pytest/data/websocket/1485975836.23-message.json'
+ datafile = "_pytest/data/websocket/1485975836.23-message.json"
data = json.loads(open(datafile).read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
- message_text = channel_general.messages[thread_ts].message_json['_rendered_text']
- assert message_text == 'generally, yep! <[color lightcyan]>[ Thread: 309 Replies: 1 ]<[color reset]>'
+ message_text = channel_general.messages[thread_ts].message_json["_rendered_text"]
+ assert (
+ message_text
+ == "generally, yep! <[color lightcyan]>[ Thread: 309 Replies: 1 ]<[color reset]>"
+ )
- datafile = '_pytest/data/websocket/1485975842.1-message.json'
+ datafile = "_pytest/data/websocket/1485975842.1-message.json"
data = json.loads(open(datafile).read())
team.ws.add(data)
realish_eventrouter.receive_ws_callback(team.team_hash, None)
realish_eventrouter.handle_next()
- message_text = channel_general.messages[thread_ts].message_json['_rendered_text']
- assert message_text == 'generally, yep! <[color lightcyan]>[ Thread: 309 Replies: 2 ]<[color reset]>'
+ message_text = channel_general.messages[thread_ts].message_json["_rendered_text"]
+ assert (
+ message_text
+ == "generally, yep! <[color lightcyan]>[ Thread: 309 Replies: 2 ]<[color reset]>"
+ )
diff --git a/_pytest/test_topic_command.py b/_pytest/test_topic_command.py
index 79a26d3..1b1c15d 100644
--- a/_pytest/test_topic_command.py
+++ b/_pytest/test_topic_command.py
@@ -6,66 +6,67 @@ from mock import patch
def test_parse_topic_without_arguments():
- channel_name, topic = parse_topic_command('/topic')
+ channel_name, topic = parse_topic_command("/topic")
assert channel_name is None
assert topic is None
def test_parse_topic_with_text():
- channel_name, topic = parse_topic_command('/topic some topic text')
+ channel_name, topic = parse_topic_command("/topic some topic text")
assert channel_name is None
- assert topic == 'some topic text'
+ assert topic == "some topic text"
def test_parse_topic_with_text_with_newline():
- channel_name, topic = parse_topic_command('/topic some topic text\nsecond line')
+ channel_name, topic = parse_topic_command("/topic some topic text\nsecond line")
assert channel_name is None
- assert topic == 'some topic text\nsecond line'
+ assert topic == "some topic text\nsecond line"
def test_parse_topic_with_delete():
- channel_name, topic = parse_topic_command('/topic -delete')
+ channel_name, topic = parse_topic_command("/topic -delete")
assert channel_name is None
- assert topic == ''
+ assert topic == ""
def test_parse_topic_with_channel():
- channel_name, topic = parse_topic_command('/topic #general')
+ channel_name, topic = parse_topic_command("/topic #general")
- assert channel_name == '#general'
+ assert channel_name == "#general"
assert topic is None
def test_parse_topic_with_channel_and_text():
- channel_name, topic = parse_topic_command(
- '/topic #general some topic text')
+ channel_name, topic = parse_topic_command("/topic #general some topic text")
- assert channel_name == '#general'
- assert topic == 'some topic text'
+ assert channel_name == "#general"
+ assert topic == "some topic text"
def test_parse_topic_with_channel_and_delete():
- channel_name, topic = parse_topic_command('/topic #general -delete')
+ channel_name, topic = parse_topic_command("/topic #general -delete")
- assert channel_name == '#general'
- assert topic == ''
+ assert channel_name == "#general"
+ assert topic == ""
def test_call_topic_without_arguments(realish_eventrouter, channel_general):
current_buffer = channel_general.channel_buffer
wee_slack.EVENTROUTER = realish_eventrouter
- command = '/topic'
+ command = "/topic"
- with patch('wee_slack.w.prnt') as fake_prnt:
+ with patch("wee_slack.w.prnt") as fake_prnt:
result = topic_command_cb(None, current_buffer, command)
fake_prnt.assert_called_with(
channel_general.channel_buffer,
- 'Topic for {} is "{}"'.format(channel_general.name, channel_general.topic['value']),
+ 'Topic for {} is "{}"'.format(
+ channel_general.name, channel_general.topic["value"]
+ ),
)
assert result == wee_slack.w.WEECHAT_RC_OK_EAT
@@ -74,9 +75,9 @@ def test_call_topic_with_unknown_channel(realish_eventrouter, team, channel_gene
current_buffer = channel_general.channel_buffer
wee_slack.EVENTROUTER = realish_eventrouter
- command = '/topic #nonexisting'
+ command = "/topic #nonexisting"
- with patch('wee_slack.w.prnt') as fake_prnt:
+ with patch("wee_slack.w.prnt") as fake_prnt:
result = topic_command_cb(None, current_buffer, command)
fake_prnt.assert_called_with(
team.channel_buffer,
@@ -89,11 +90,14 @@ def test_call_topic_with_channel_and_string(realish_eventrouter, channel_general
current_buffer = channel_general.channel_buffer
wee_slack.EVENTROUTER = realish_eventrouter
- command = '/topic #general new topic'
+ command = "/topic #general new topic"
result = topic_command_cb(None, current_buffer, command)
request = realish_eventrouter.queue[-1]
- assert request.request == 'conversations.setTopic'
+ assert request.request == "conversations.setTopic"
assert request.post_data == {
- 'channel': 'C407ABS94', 'token': 'xoxs-token', 'topic': 'new topic'}
+ "channel": "C407ABS94",
+ "token": "xoxs-token",
+ "topic": "new topic",
+ }
assert result == wee_slack.w.WEECHAT_RC_OK_EAT
diff --git a/_pytest/test_unfurl.py b/_pytest/test_unfurl.py
index eb8fe27..e8043a8 100644
--- a/_pytest/test_unfurl.py
+++ b/_pytest/test_unfurl.py
@@ -6,166 +6,173 @@ import time
import wee_slack
import os
-os.environ['TZ'] = 'UTC'
+os.environ["TZ"] = "UTC"
-@pytest.mark.parametrize('case', (
- {
- 'input': "foo",
- 'output': "foo",
- },
- {
- 'input': "<!channel>",
- 'output': "@channel",
- },
- {
- 'input': "<!everyone>",
- 'output': "@everyone",
- },
- {
- 'input': "<!group>",
- 'output': "@group",
- },
- {
- 'input': "<!here>",
- 'output': "@here",
- },
- {
- 'input': "<@U407ABLLW|@othernick>: foo",
- 'output': "@alice: foo",
- },
- {
- 'input': "<@UNKNOWN|@othernick>: foo",
- 'output': "@othernick: foo",
- },
- {
- 'input': "foo <#C407ABS94|otherchannel> foo",
- 'output': "foo #general foo",
- },
- {
- 'input': "foo <#UNKNOWN|otherchannel> foo",
- 'output': "foo #otherchannel foo",
- },
- {
- 'input': "url: <https://example.com|fallback> suffix",
- 'output': "url: https://example.com suffix",
- 'ignore_alt_text': True,
- },
- {
- 'input': "url: <https://example.com|example> suffix",
- 'output': "url: https://example.com (example) suffix",
- 'auto_link_display': 'both',
- },
- {
- 'input': "url: <https://example.com|example with spaces> suffix",
- 'output': "url: https://example.com (example with spaces) suffix",
- 'auto_link_display': 'both',
- },
- {
- 'input': "url: <https://example.com|example.com> suffix",
- 'output': "url: https://example.com (example.com) suffix",
- 'auto_link_display': 'both',
- },
- {
- 'input': "url: <mailto:name@example.com|name@example.com> suffix",
- 'output': "url: mailto:name@example.com (name@example.com) suffix",
- 'auto_link_display': 'both',
- },
- {
- 'input': "url: <https://example.com|example.com> suffix",
- 'output': "url: example.com suffix",
- 'auto_link_display': 'text',
- },
- {
- 'input': "url: <https://example.com|different text> suffix",
- 'output': "url: https://example.com (different text) suffix",
- 'auto_link_display': 'text',
- },
- {
- 'input': "url: <mailto:name@example.com|name@example.com> suffix",
- 'output': "url: name@example.com suffix",
- 'auto_link_display': 'text',
- },
- {
- 'input': "url: <https://example.com|different text> suffix",
- 'output': "url: https://example.com (different text) suffix",
- 'auto_link_display': 'url',
- },
- {
- 'input': "url: <https://example.com|example.com> suffix",
- 'output': "url: https://example.com suffix",
- 'auto_link_display': 'url',
- },
- {
- 'input': "url: <mailto:name@example.com|name@example.com> suffix",
- 'output': "url: mailto:name@example.com suffix",
- 'auto_link_display': 'url',
- },
- {
- 'input': "<@U407ABLLW> multiple unfurl <https://example.com|example with spaces>",
- 'output': "@alice multiple unfurl https://example.com (example with spaces)",
- 'auto_link_display': 'both',
- },
- {
- 'input': "url with equal fallback: <https://example.com|https://example.com> suffix",
- 'output': "url with equal fallback: https://example.com suffix",
- 'auto_link_display': 'both',
- },
- {
- 'input': "try the #general channel",
- 'output': "try the #general channel",
- },
- {
- 'input': "<@U407ABLLW> I think 3 > 2",
- 'output': "@alice I think 3 > 2",
- },
- {
- 'input': "<!subteam^TGX0ALBK3|@othersubteam> This is announcement for the dev team",
- 'output': "@test This is announcement for the dev team"
- },
- {
- 'input': "<!subteam^UNKNOWN|@othersubteam> This is announcement for the dev team",
- 'output': "@othersubteam This is announcement for the dev team"
- },
- {
- 'input': "Ends <!date^1577880000^{date_num} - {date} - {date_short} - {date_long}|Jan 01, 2020>.",
- 'output': "Ends 2020-01-01 - January 01, 2020 - Jan 01, 2020 - Wednesday, January 01, 2020."
- },
- {
- 'input': "Ends <!date^1577880000^{time} - {time_secs}|12:00 PM>.",
- 'output': "Ends 12:00 - 12:00:00."
- },
- {
- 'input': "Ends <!date^1577880000^{date_num} {invalid_token}>.",
- 'output': "Ends 2020-01-01 {invalid_token}."
- },
- {
- 'input': "Ends <!date^1577880000^{date_num}^http://github.com>.",
- 'output': "Ends 2020-01-01 (http://github.com)."
- },
- {
- 'input': "Ends <!date^{}^{{date_pretty}} - {{date_short_pretty}} - {{date_long_pretty}}>.".format(
- int(time.mktime(datetime.today().timetuple()))),
- 'output': "Ends today - today - today."
- },
- {
- 'input': "Ends <!date^{}^{{date_pretty}} - {{date_short_pretty}} - {{date_long_pretty}}>.".format(
- int(time.mktime((datetime.today() - timedelta(days=1)).timetuple()))),
- 'output': "Ends yesterday - yesterday - yesterday."
- },
- {
- 'input': "Ends <!date^{}^{{date_pretty}} - {{date_short_pretty}} - {{date_long_pretty}}>.".format(
- int(time.mktime((datetime.today() + timedelta(days=1)).timetuple()))),
- 'output': "Ends tomorrow - tomorrow - tomorrow."
- },
- {
- 'input': "Ends <!date^1577880000^{date_pretty} - {date_short_pretty} - {date_long_pretty}>.",
- 'output': "Ends January 01, 2020 - Jan 01, 2020 - Wednesday, January 01, 2020."
- }
-))
+
+@pytest.mark.parametrize(
+ "case",
+ (
+ {
+ "input": "foo",
+ "output": "foo",
+ },
+ {
+ "input": "<!channel>",
+ "output": "@channel",
+ },
+ {
+ "input": "<!everyone>",
+ "output": "@everyone",
+ },
+ {
+ "input": "<!group>",
+ "output": "@group",
+ },
+ {
+ "input": "<!here>",
+ "output": "@here",
+ },
+ {
+ "input": "<@U407ABLLW|@othernick>: foo",
+ "output": "@alice: foo",
+ },
+ {
+ "input": "<@UNKNOWN|@othernick>: foo",
+ "output": "@othernick: foo",
+ },
+ {
+ "input": "foo <#C407ABS94|otherchannel> foo",
+ "output": "foo #general foo",
+ },
+ {
+ "input": "foo <#UNKNOWN|otherchannel> foo",
+ "output": "foo #otherchannel foo",
+ },
+ {
+ "input": "url: <https://example.com|fallback> suffix",
+ "output": "url: https://example.com suffix",
+ "ignore_alt_text": True,
+ },
+ {
+ "input": "url: <https://example.com|example> suffix",
+ "output": "url: https://example.com (example) suffix",
+ "auto_link_display": "both",
+ },
+ {
+ "input": "url: <https://example.com|example with spaces> suffix",
+ "output": "url: https://example.com (example with spaces) suffix",
+ "auto_link_display": "both",
+ },
+ {
+ "input": "url: <https://example.com|example.com> suffix",
+ "output": "url: https://example.com (example.com) suffix",
+ "auto_link_display": "both",
+ },
+ {
+ "input": "url: <mailto:name@example.com|name@example.com> suffix",
+ "output": "url: mailto:name@example.com (name@example.com) suffix",
+ "auto_link_display": "both",
+ },
+ {
+ "input": "url: <https://example.com|example.com> suffix",
+ "output": "url: example.com suffix",
+ "auto_link_display": "text",
+ },
+ {
+ "input": "url: <https://example.com|different text> suffix",
+ "output": "url: https://example.com (different text) suffix",
+ "auto_link_display": "text",
+ },
+ {
+ "input": "url: <mailto:name@example.com|name@example.com> suffix",
+ "output": "url: name@example.com suffix",
+ "auto_link_display": "text",
+ },
+ {
+ "input": "url: <https://example.com|different text> suffix",
+ "output": "url: https://example.com (different text) suffix",
+ "auto_link_display": "url",
+ },
+ {
+ "input": "url: <https://example.com|example.com> suffix",
+ "output": "url: https://example.com suffix",
+ "auto_link_display": "url",
+ },
+ {
+ "input": "url: <mailto:name@example.com|name@example.com> suffix",
+ "output": "url: mailto:name@example.com suffix",
+ "auto_link_display": "url",
+ },
+ {
+ "input": "<@U407ABLLW> multiple unfurl <https://example.com|example with spaces>",
+ "output": "@alice multiple unfurl https://example.com (example with spaces)",
+ "auto_link_display": "both",
+ },
+ {
+ "input": "url with equal fallback: <https://example.com|https://example.com> suffix",
+ "output": "url with equal fallback: https://example.com suffix",
+ "auto_link_display": "both",
+ },
+ {
+ "input": "try the #general channel",
+ "output": "try the #general channel",
+ },
+ {
+ "input": "<@U407ABLLW> I think 3 > 2",
+ "output": "@alice I think 3 > 2",
+ },
+ {
+ "input": "<!subteam^TGX0ALBK3|@othersubteam> This is announcement for the dev team",
+ "output": "@test This is announcement for the dev team",
+ },
+ {
+ "input": "<!subteam^UNKNOWN|@othersubteam> This is announcement for the dev team",
+ "output": "@othersubteam This is announcement for the dev team",
+ },
+ {
+ "input": "Ends <!date^1577880000^{date_num} - {date} - {date_short} - {date_long}|Jan 01, 2020>.",
+ "output": "Ends 2020-01-01 - January 01, 2020 - Jan 01, 2020 - Wednesday, January 01, 2020.",
+ },
+ {
+ "input": "Ends <!date^1577880000^{time} - {time_secs}|12:00 PM>.",
+ "output": "Ends 12:00 - 12:00:00.",
+ },
+ {
+ "input": "Ends <!date^1577880000^{date_num} {invalid_token}>.",
+ "output": "Ends 2020-01-01 {invalid_token}.",
+ },
+ {
+ "input": "Ends <!date^1577880000^{date_num}^http://github.com>.",
+ "output": "Ends 2020-01-01 (http://github.com).",
+ },
+ {
+ "input": "Ends <!date^{}^{{date_pretty}} - {{date_short_pretty}} - {{date_long_pretty}}>.".format(
+ int(time.mktime(datetime.today().timetuple()))
+ ),
+ "output": "Ends today - today - today.",
+ },
+ {
+ "input": "Ends <!date^{}^{{date_pretty}} - {{date_short_pretty}} - {{date_long_pretty}}>.".format(
+ int(time.mktime((datetime.today() - timedelta(days=1)).timetuple()))
+ ),
+ "output": "Ends yesterday - yesterday - yesterday.",
+ },
+ {
+ "input": "Ends <!date^{}^{{date_pretty}} - {{date_short_pretty}} - {{date_long_pretty}}>.".format(
+ int(time.mktime((datetime.today() + timedelta(days=1)).timetuple()))
+ ),
+ "output": "Ends tomorrow - tomorrow - tomorrow.",
+ },
+ {
+ "input": "Ends <!date^1577880000^{date_pretty} - {date_short_pretty} - {date_long_pretty}>.",
+ "output": "Ends January 01, 2020 - Jan 01, 2020 - Wednesday, January 01, 2020.",
+ },
+ ),
+)
def test_unfurl_refs(case, realish_eventrouter):
wee_slack.EVENTROUTER = realish_eventrouter
- wee_slack.config.unfurl_ignore_alt_text = case.get('ignore_alt_text')
- wee_slack.config.unfurl_auto_link_display = case.get('auto_link_display')
+ wee_slack.config.unfurl_ignore_alt_text = case.get("ignore_alt_text")
+ wee_slack.config.unfurl_auto_link_display = case.get("auto_link_display")
- result = wee_slack.unfurl_refs(case['input'])
- assert result == case['output']
+ result = wee_slack.unfurl_refs(case["input"])
+ assert result == case["output"]
diff --git a/_pytest/test_unwrap_attachments.py b/_pytest/test_unwrap_attachments.py
index aed696c..d4116eb 100644
--- a/_pytest/test_unwrap_attachments.py
+++ b/_pytest/test_unwrap_attachments.py
@@ -4,322 +4,467 @@ import wee_slack
import pytest
-@pytest.mark.parametrize('case', (
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- }]},
- 'input_text_before': "Text before",
- 'output': "\n".join([
- "",
- "| Title",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text',
- 'title_link': 'http://title.link',
- 'from_url': 'http://from.url',
- 'fallback': 'Fallback',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Title (http://title.link)",
- "| http://from.url",
- "| Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text',
- 'title_link': 'http://title.link',
- 'image_url': 'http://image.url',
- 'fallback': 'Fallback',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Title (http://title.link)",
- "| Attachment text",
- "| http://image.url",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text',
- 'title_link': 'http://link?a=1&b=2',
- 'from_url': 'http://link?a=1&b=2',
- 'image_url': 'http://link?a=1&b=2',
- }]},
- 'input_text_before': "http://link?a=1&amp;b=2",
- 'output': "\n".join([
- "",
- "| Title",
- "| Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text',
- 'title_link': 'http://link?a=1&amp;b=2',
- 'from_url': 'http://link?a=1&amp;b=2',
- 'image_url': 'http://link?a=1&amp;b=2',
- }]},
- 'input_text_before': "http://link?a=1&amp;b=2",
- 'output': "\n".join([
- "",
- "| Title",
- "| Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text',
- 'title_link': 'http://link',
- 'from_url': 'http://link',
- 'image_url': 'http://link',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Title (http://link)",
- "| Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text',
- 'from_url': 'http://link',
- 'image_url': 'http://link',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Title",
- "| http://link",
- "| Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'text': 'Attachment text\n\n\nWith multiple lines',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Title",
- "| Attachment text",
- "| With multiple lines",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'author_name': 'Author',
- 'pretext': 'Pretext',
- 'text': 'Attachment text',
- 'title_link': 'http://title.link',
- 'from_url': 'http://from.url',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Pretext",
- "| Author: Title (http://title.link)",
- "| http://from.url",
- "| Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'author_name': 'Author',
- 'text': 'Attachment text',
- 'title_link': 'http://title.link',
- 'from_url': 'http://from.url',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| http://from.url",
- "| Author: Attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'fallback': 'Fallback',
- }]},
- 'input_text_before': "",
- 'output': "| Fallback",
- },
- {
- 'input_message': {'attachments': [{
- 'fallback': 'Fallback',
- 'title_link': 'http://link',
- }]},
- 'input_text_before': "http://link",
- 'output': "",
- },
- {
- 'input_message': {'attachments': [{
- 'fallback': 'Fallback',
- 'from_url': 'http://link',
- }]},
- 'input_text_before': "http://link",
- 'output': "",
- },
- {
- 'input_message': {'attachments': [{
- 'fallback': 'Fallback',
- 'image_url': 'http://link',
- }]},
- 'input_text_before': "http://link",
- 'output': "",
- },
- {
- 'input_message': {'attachments': [{
- 'text': 'Some message',
- 'footer': 'Thread in #general'
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Some message",
- "| Thread in #general",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'ts': 1584986782,
- 'text': 'Some message',
- 'footer': 'Thread in #general'
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Some message",
- "| Thread in #general | Mar 23, 2020",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'ts': '1584986782.261400',
- 'text': 'Some message',
- 'footer': 'Thread in #general'
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Some message",
- "| Thread in #general | Mar 23, 2020",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'text': 'Original message',
- 'files': [
- {
- 'title': 'File',
- 'url_private': 'http://link',
- }
- ],
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Original message",
- "| http://link (File)",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'fields': [{
- 'title': 'First field title',
- 'value': 'First field value',
- }, {
- 'title': '',
- 'value': 'Second field value',
- }],
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Title",
- "| First field title: First field value",
- "| Second field value",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'First attachment title',
- 'text': 'First attachment text',
- 'title_link': 'http://title.link.1',
- 'from_url': 'http://from.url.1',
- }, {
- 'title': 'Second attachment title',
- 'text': 'Second attachment text',
- 'title_link': 'http://title.link.2',
- 'from_url': 'http://from.url.2',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| First attachment title (http://title.link.1)",
- "| http://from.url.1",
- "| First attachment text",
- "| Second attachment title (http://title.link.2)",
- "| http://from.url.2",
- "| Second attachment text",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'color': 'ff0000',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "<[color 16711680]>|<[color reset]> Title",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'title': 'Title',
- 'color': '#ff0000',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "<[color 16711680]>|<[color reset]> Title",
- ]),
- },
- {
- 'input_message': {'attachments': [{
- 'text': 'Attachment text',
- 'original_url': 'http://from.url',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Attachment text",
- ]),
- 'link_previews': True
- },
- {
- 'input_message': {'attachments': [{
- 'text': 'Attachment text',
- 'original_url': 'http://from.url',
- }]},
- 'input_text_before': "",
- 'output': '',
- 'link_previews': False
- },
- {
- 'input_message': {'attachments': [{
- 'text': 'Attachment text',
- }]},
- 'input_text_before': "",
- 'output': "\n".join([
- "| Attachment text",
- ]),
- 'link_previews': False
- },
-))
+@pytest.mark.parametrize(
+ "case",
+ (
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ }
+ ]
+ },
+ "input_text_before": "Text before",
+ "output": "\n".join(
+ [
+ "",
+ "| Title",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text",
+ "title_link": "http://title.link",
+ "from_url": "http://from.url",
+ "fallback": "Fallback",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Title (http://title.link)",
+ "| http://from.url",
+ "| Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text",
+ "title_link": "http://title.link",
+ "image_url": "http://image.url",
+ "fallback": "Fallback",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Title (http://title.link)",
+ "| Attachment text",
+ "| http://image.url",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text",
+ "title_link": "http://link?a=1&b=2",
+ "from_url": "http://link?a=1&b=2",
+ "image_url": "http://link?a=1&b=2",
+ }
+ ]
+ },
+ "input_text_before": "http://link?a=1&amp;b=2",
+ "output": "\n".join(
+ [
+ "",
+ "| Title",
+ "| Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text",
+ "title_link": "http://link?a=1&amp;b=2",
+ "from_url": "http://link?a=1&amp;b=2",
+ "image_url": "http://link?a=1&amp;b=2",
+ }
+ ]
+ },
+ "input_text_before": "http://link?a=1&amp;b=2",
+ "output": "\n".join(
+ [
+ "",
+ "| Title",
+ "| Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text",
+ "title_link": "http://link",
+ "from_url": "http://link",
+ "image_url": "http://link",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Title (http://link)",
+ "| Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text",
+ "from_url": "http://link",
+ "image_url": "http://link",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Title",
+ "| http://link",
+ "| Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "text": "Attachment text\n\n\nWith multiple lines",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Title",
+ "| Attachment text",
+ "| With multiple lines",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "author_name": "Author",
+ "pretext": "Pretext",
+ "text": "Attachment text",
+ "title_link": "http://title.link",
+ "from_url": "http://from.url",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Pretext",
+ "| Author: Title (http://title.link)",
+ "| http://from.url",
+ "| Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "author_name": "Author",
+ "text": "Attachment text",
+ "title_link": "http://title.link",
+ "from_url": "http://from.url",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| http://from.url",
+ "| Author: Attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "fallback": "Fallback",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "| Fallback",
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "fallback": "Fallback",
+ "title_link": "http://link",
+ }
+ ]
+ },
+ "input_text_before": "http://link",
+ "output": "",
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "fallback": "Fallback",
+ "from_url": "http://link",
+ }
+ ]
+ },
+ "input_text_before": "http://link",
+ "output": "",
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "fallback": "Fallback",
+ "image_url": "http://link",
+ }
+ ]
+ },
+ "input_text_before": "http://link",
+ "output": "",
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {"text": "Some message", "footer": "Thread in #general"}
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Some message",
+ "| Thread in #general",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "ts": 1584986782,
+ "text": "Some message",
+ "footer": "Thread in #general",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Some message",
+ "| Thread in #general | Mar 23, 2020",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "ts": "1584986782.261400",
+ "text": "Some message",
+ "footer": "Thread in #general",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Some message",
+ "| Thread in #general | Mar 23, 2020",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "text": "Original message",
+ "files": [
+ {
+ "title": "File",
+ "url_private": "http://link",
+ }
+ ],
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Original message",
+ "| http://link (File)",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "fields": [
+ {
+ "title": "First field title",
+ "value": "First field value",
+ },
+ {
+ "title": "",
+ "value": "Second field value",
+ },
+ ],
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Title",
+ "| First field title: First field value",
+ "| Second field value",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "First attachment title",
+ "text": "First attachment text",
+ "title_link": "http://title.link.1",
+ "from_url": "http://from.url.1",
+ },
+ {
+ "title": "Second attachment title",
+ "text": "Second attachment text",
+ "title_link": "http://title.link.2",
+ "from_url": "http://from.url.2",
+ },
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| First attachment title (http://title.link.1)",
+ "| http://from.url.1",
+ "| First attachment text",
+ "| Second attachment title (http://title.link.2)",
+ "| http://from.url.2",
+ "| Second attachment text",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "color": "ff0000",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "<[color 16711680]>|<[color reset]> Title",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "title": "Title",
+ "color": "#ff0000",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "<[color 16711680]>|<[color reset]> Title",
+ ]
+ ),
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "text": "Attachment text",
+ "original_url": "http://from.url",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Attachment text",
+ ]
+ ),
+ "link_previews": True,
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "text": "Attachment text",
+ "original_url": "http://from.url",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "",
+ "link_previews": False,
+ },
+ {
+ "input_message": {
+ "attachments": [
+ {
+ "text": "Attachment text",
+ }
+ ]
+ },
+ "input_text_before": "",
+ "output": "\n".join(
+ [
+ "| Attachment text",
+ ]
+ ),
+ "link_previews": False,
+ },
+ ),
+)
def test_unwrap_attachments(case):
- wee_slack.config.link_previews = case.get('link_previews')
+ wee_slack.config.link_previews = case.get("link_previews")
result = wee_slack.unwrap_attachments(
- case['input_message'], case['input_text_before'])
- assert result == case['output']
+ case["input_message"], case["input_text_before"]
+ )
+ assert result == case["output"]
diff --git a/_pytest/test_utf8_helpers.py b/_pytest/test_utf8_helpers.py
index a2dea42..271b84b 100644
--- a/_pytest/test_utf8_helpers.py
+++ b/_pytest/test_utf8_helpers.py
@@ -7,79 +7,82 @@ from collections import OrderedDict
from wee_slack import decode_from_utf8, encode_to_utf8, utf8_decode
-b_ae = 'æ'.encode('utf-8')
-b_oe = 'ø'.encode('utf-8')
-b_aa = 'å'.encode('utf-8')
+b_ae = "æ".encode("utf-8")
+b_oe = "ø".encode("utf-8")
+b_aa = "å".encode("utf-8")
b_word = b_ae + b_oe + b_aa
if sys.version_info.major > 2:
+
def test_decode_should_not_transform_str():
- assert 'æøå' == decode_from_utf8('æøå')
+ assert "æøå" == decode_from_utf8("æøå")
def test_decode_should_not_transform_bytes():
assert b_word == decode_from_utf8(b_word)
def test_encode_should_not_transform_str():
- assert 'æøå' == encode_to_utf8('æøå')
+ assert "æøå" == encode_to_utf8("æøå")
def test_encode_should_not_transform_bytes():
assert b_word == encode_to_utf8(b_word)
+
else:
+
def test_decode_preserves_string_without_utf8():
- assert 'test' == decode_from_utf8(b'test')
+ assert "test" == decode_from_utf8(b"test")
def test_decode_preserves_unicode_strings():
- assert 'æøå' == decode_from_utf8('æøå')
+ assert "æøå" == decode_from_utf8("æøå")
def test_decode_preserves_mapping_type():
- value_dict = {'a': 'x', 'b': 'y', 'c': 'z'}
+ value_dict = {"a": "x", "b": "y", "c": "z"}
value_ord_dict = OrderedDict(value_dict)
assert type(value_dict) == type(decode_from_utf8(value_dict))
assert type(value_ord_dict) == type(decode_from_utf8(value_ord_dict))
def test_decode_preserves_iterable_type():
- value_set = {'a', 'b', 'c'}
- value_tuple = ('a', 'b', 'c')
+ value_set = {"a", "b", "c"}
+ value_tuple = ("a", "b", "c")
assert type(value_set) == type(decode_from_utf8(value_set))
assert type(value_tuple) == type(decode_from_utf8(value_tuple))
def test_decodes_utf8_string_to_unicode():
- assert 'æøå' == decode_from_utf8(b_word)
+ assert "æøå" == decode_from_utf8(b_word)
def test_decodes_utf8_dict_to_unicode():
- assert {'æ': 'å', 'ø': 'å'} == decode_from_utf8({b_ae: b_aa, b_oe: b_aa})
+ assert {"æ": "å", "ø": "å"} == decode_from_utf8({b_ae: b_aa, b_oe: b_aa})
def test_decodes_utf8_list_to_unicode():
- assert ['æ', 'ø', 'å'] == decode_from_utf8([b_ae, b_oe, b_aa])
+ assert ["æ", "ø", "å"] == decode_from_utf8([b_ae, b_oe, b_aa])
def test_encode_preserves_string_without_utf8():
- assert b'test' == encode_to_utf8('test')
+ assert b"test" == encode_to_utf8("test")
def test_encode_preserves_byte_strings():
assert b_word == encode_to_utf8(b_word)
def test_encode_preserves_mapping_type():
- value_dict = {'a': 'x', 'b': 'y', 'c': 'z'}
+ value_dict = {"a": "x", "b": "y", "c": "z"}
value_ord_dict = OrderedDict(value_dict)
assert type(value_dict) == type(encode_to_utf8(value_dict))
assert type(value_ord_dict) == type(encode_to_utf8(value_ord_dict))
def test_encode_preserves_iterable_type():
- value_set = {'a', 'b', 'c'}
- value_tuple = ('a', 'b', 'c')
+ value_set = {"a", "b", "c"}
+ value_tuple = ("a", "b", "c")
assert type(value_set) == type(encode_to_utf8(value_set))
assert type(value_tuple) == type(encode_to_utf8(value_tuple))
def test_encodes_utf8_string_to_unicode():
- assert b_word == encode_to_utf8('æøå')
+ assert b_word == encode_to_utf8("æøå")
def test_encodes_utf8_dict_to_unicode():
- assert {b_ae: b_aa, b_oe: b_aa} == encode_to_utf8({'æ': 'å', 'ø': 'å'})
+ assert {b_ae: b_aa, b_oe: b_aa} == encode_to_utf8({"æ": "å", "ø": "å"})
def test_encodes_utf8_list_to_unicode():
- assert [b_ae, b_oe, b_aa] == encode_to_utf8(['æ', 'ø', 'å'])
+ assert [b_ae, b_oe, b_aa] == encode_to_utf8(["æ", "ø", "å"])
@utf8_decode
def method_with_utf8_decode(*args, **kwargs):
diff --git a/generate_docs.py b/generate_docs.py
index 51947f9..3a421f1 100755
--- a/generate_docs.py
+++ b/generate_docs.py
@@ -9,8 +9,10 @@ import wee_slack
cmds = wee_slack.EventRouter().cmds
options = wee_slack.PluginConfig.default_settings
-with open('docs/Commands.md', 'w') as file_cmds:
- file_cmds.write(dedent("""
+with open("docs/Commands.md", "w") as file_cmds:
+ file_cmds.write(
+ dedent(
+ """
# Commands
These are the commands made available by this script. In In addition to
@@ -22,12 +24,16 @@ with open('docs/Commands.md', 'w') as file_cmds:
## Available commands:
- """).lstrip())
+ """
+ ).lstrip()
+ )
for name, cmd in sorted(cmds.items()):
- doc = dedent(cmd.__doc__ or '').strip()
- command, helptext = doc.split('\n', 1)
- file_cmds.write(dedent("""
+ doc = dedent(cmd.__doc__ or "").strip()
+ command, helptext = doc.split("\n", 1)
+ file_cmds.write(
+ dedent(
+ """
### {}
```
@@ -36,10 +42,16 @@ with open('docs/Commands.md', 'w') as file_cmds:
{}
- """).lstrip().format(name, command, helptext))
+ """
+ )
+ .lstrip()
+ .format(name, command, helptext)
+ )
-with open('docs/Options.md', 'w') as file_options:
- file_options.write(dedent("""
+with open("docs/Options.md", "w") as file_options:
+ file_options.write(
+ dedent(
+ """
# Options
You can set these options by using:
@@ -58,14 +70,22 @@ with open('docs/Options.md', 'w') as file_options:
## Available options:
- """).lstrip())
+ """
+ ).lstrip()
+ )
for name, option in sorted(options.items()):
- file_options.write(dedent("""
+ file_options.write(
+ dedent(
+ """
### {}
**Default:** `{}`
**Description:** {}
- """).lstrip().format(name, option.default, option.desc))
+ """
+ )
+ .lstrip()
+ .format(name, option.default, option.desc)
+ )
diff --git a/generate_weemoji.py b/generate_weemoji.py
index 022cd4b..a273963 100755
--- a/generate_weemoji.py
+++ b/generate_weemoji.py
@@ -5,15 +5,17 @@ import sys
all_emojis = json.loads(sys.stdin.read())
+
def convert_unicode_string(emoji_dict):
for k, v in emoji_dict.items():
- if k == 'unicode':
- emoji_dict[k] = ''.join([chr(int(x, 16)) for x in v.split('-')])
+ if k == "unicode":
+ emoji_dict[k] = "".join([chr(int(x, 16)) for x in v.split("-")])
if type(v) == dict:
convert_unicode_string(v)
+
convert_unicode_string(all_emojis)
-with open('weemoji.json', 'w') as weemoji:
+with open("weemoji.json", "w") as weemoji:
json.dump(all_emojis, weemoji, indent=2, sort_keys=True)
- weemoji.write('\n')
+ weemoji.write("\n")
diff --git a/wee_slack.py b/wee_slack.py
index 7ae1c5b..c9d0c60 100644
--- a/wee_slack.py
+++ b/wee_slack.py
@@ -35,7 +35,7 @@ sys.modules["numpy"] = None
from websocket import ABNF, create_connection, WebSocketConnectionClosedException
try:
- basestring # Python 2
+ basestring # Python 2
unicode
str = unicode
except NameError: # Python 3
@@ -45,6 +45,7 @@ try:
from collections.abc import Mapping, Reversible, KeysView, ItemsView, ValuesView
except:
from collections import Mapping, KeysView, ItemsView, ValuesView
+
Reversible = object
try:
@@ -100,7 +101,7 @@ SLACK_API_TRANSLATOR = {
"join": "conversations.join",
"leave": "conversations.leave",
"mark": "conversations.mark",
- "info": "conversations.info"
+ "info": "conversations.info",
},
"private": {
"history": "conversations.history",
@@ -121,9 +122,7 @@ SLACK_API_TRANSLATOR = {
"join": None,
"leave": None,
"mark": "subscriptions.thread.mark",
- }
-
-
+ },
}
CONFIG_PREFIX = "plugins.var.python." + SCRIPT_NAME
@@ -135,11 +134,13 @@ def slack_buffer_or_ignore(f):
"""
Only run this function if we're in a slack buffer, else ignore
"""
+
@wraps(f)
def wrapper(data, current_buffer, *args, **kwargs):
if current_buffer not in EVENTROUTER.weechat_controller.buffers:
return w.WEECHAT_RC_OK
return f(data, current_buffer, *args, **kwargs)
+
return wrapper
@@ -147,13 +148,20 @@ def slack_buffer_required(f):
"""
Only run this function if we're in a slack buffer, else print error
"""
+
@wraps(f)
def wrapper(data, current_buffer, *args, **kwargs):
if current_buffer not in EVENTROUTER.weechat_controller.buffers:
- command_name = f.__name__.replace('command_', '', 1)
- w.prnt('', 'slack: command "{}" must be executed on slack buffer'.format(command_name))
+ command_name = f.__name__.replace("command_", "", 1)
+ w.prnt(
+ "",
+ 'slack: command "{}" must be executed on slack buffer'.format(
+ command_name
+ ),
+ )
return w.WEECHAT_RC_ERROR
return f(data, current_buffer, *args, **kwargs)
+
return wrapper
@@ -162,9 +170,11 @@ def utf8_decode(f):
Decode all arguments from byte strings to unicode strings. Use this for
functions called from outside of this script, e.g. callbacks from weechat.
"""
+
@wraps(f)
def wrapper(*args, **kwargs):
return f(*decode_from_utf8(args), **decode_from_utf8(kwargs))
+
return wrapper
@@ -176,7 +186,7 @@ sslopt_ca_certs = {}
if hasattr(ssl, "get_default_verify_paths") and callable(ssl.get_default_verify_paths):
ssl_defaults = ssl.get_default_verify_paths()
if ssl_defaults.cafile is not None:
- sslopt_ca_certs = {'ca_certs': ssl_defaults.cafile}
+ sslopt_ca_certs = {"ca_certs": ssl_defaults.cafile}
EMOJI = {}
EMOJI_WITH_SKIN_TONES_REVERSE = {}
@@ -188,7 +198,7 @@ def encode_to_utf8(data):
if sys.version_info.major > 2:
return data
elif isinstance(data, unicode):
- return data.encode('utf-8')
+ return data.encode("utf-8")
if isinstance(data, bytes):
return data
elif isinstance(data, collections.Mapping):
@@ -203,7 +213,7 @@ def decode_from_utf8(data):
if sys.version_info.major > 2:
return data
elif isinstance(data, bytes):
- return data.decode('utf-8')
+ return data.decode("utf-8")
if isinstance(data, unicode):
return data
elif isinstance(data, collections.Mapping):
@@ -226,6 +236,7 @@ class WeechatWrapper(object):
if result == self.wrapped_class:
return self
return decode_from_utf8(result)
+
return hooked
# Encode and decode everything sent to/received from weechat. We use the
@@ -241,12 +252,14 @@ class WeechatWrapper(object):
# first, we want to disable the prefix, which is done by specifying a space.
def prnt_date_tags(self, buffer, date, tags, message):
message = message.replace("\n", "\n \t")
- return self.wrap_for_utf8(self.wrapped_class.prnt_date_tags)(buffer, date, tags, message)
+ return self.wrap_for_utf8(self.wrapped_class.prnt_date_tags)(
+ buffer, date, tags, message
+ )
class ProxyWrapper(object):
def __init__(self):
- self.proxy_name = w.config_string(w.config_get('weechat.network.proxy_curl'))
+ self.proxy_name = w.config_string(w.config_get("weechat.network.proxy_curl"))
self.proxy_string = ""
self.proxy_type = ""
self.proxy_address = ""
@@ -257,15 +270,30 @@ class ProxyWrapper(object):
if self.proxy_name:
self.proxy_string = "weechat.proxy.{}".format(self.proxy_name)
- self.proxy_type = w.config_string(w.config_get("{}.type".format(self.proxy_string)))
+ self.proxy_type = w.config_string(
+ w.config_get("{}.type".format(self.proxy_string))
+ )
if self.proxy_type == "http":
- self.proxy_address = w.config_string(w.config_get("{}.address".format(self.proxy_string)))
- self.proxy_port = w.config_integer(w.config_get("{}.port".format(self.proxy_string)))
- self.proxy_user = w.config_string(w.config_get("{}.username".format(self.proxy_string)))
- self.proxy_password = w.config_string(w.config_get("{}.password".format(self.proxy_string)))
+ self.proxy_address = w.config_string(
+ w.config_get("{}.address".format(self.proxy_string))
+ )
+ self.proxy_port = w.config_integer(
+ w.config_get("{}.port".format(self.proxy_string))
+ )
+ self.proxy_user = w.config_string(
+ w.config_get("{}.username".format(self.proxy_string))
+ )
+ self.proxy_password = w.config_string(
+ w.config_get("{}.password".format(self.proxy_string))
+ )
self.has_proxy = True
else:
- w.prnt("", "\nWarning: weechat.network.proxy_curl is set to {} type (name : {}, conf string : {}). Only HTTP proxy is supported.\n\n".format(self.proxy_type, self.proxy_name, self.proxy_string))
+ w.prnt(
+ "",
+ "\nWarning: weechat.network.proxy_curl is set to {} type (name : {}, conf string : {}). Only HTTP proxy is supported.\n\n".format(
+ self.proxy_type, self.proxy_name, self.proxy_string
+ ),
+ )
def curl(self):
if not self.has_proxy:
@@ -315,28 +343,30 @@ class ValuesViewReversible(ValuesView, Reversible):
##### Helpers
-def colorize_string(color, string, reset_color='reset'):
+def colorize_string(color, string, reset_color="reset"):
if color:
return w.color(color) + string + w.color(reset_color)
else:
return string
-def print_error(message, buffer='', warning=False):
- prefix = 'Warning' if warning else 'Error'
- w.prnt(buffer, '{}{}: {}'.format(w.prefix('error'), prefix, message))
+def print_error(message, buffer="", warning=False):
+ prefix = "Warning" if warning else "Error"
+ w.prnt(buffer, "{}{}: {}".format(w.prefix("error"), prefix, message))
def print_message_not_found_error(msg_id):
if msg_id:
- print_error("Invalid id given, must be an existing id or a number greater " +
- "than 0 and less than the number of messages in the channel")
+ print_error(
+ "Invalid id given, must be an existing id or a number greater "
+ + "than 0 and less than the number of messages in the channel"
+ )
else:
print_error("No messages found in channel")
def token_for_print(token):
- return '{}...{}'.format(token[:15], token[-10:])
+ return "{}...{}".format(token[:15], token[-10:])
def format_exc_tb():
@@ -345,7 +375,7 @@ def format_exc_tb():
def format_exc_only():
etype, value, _ = sys.exc_info()
- return ''.join(decode_from_utf8(traceback.format_exception_only(etype, value)))
+ return "".join(decode_from_utf8(traceback.format_exception_only(etype, value)))
def get_localvar_type(slack_type):
@@ -361,40 +391,54 @@ def get_nick_color(nick):
def get_thread_color(thread_id):
- if config.color_thread_suffix == 'multiple':
+ if config.color_thread_suffix == "multiple":
return get_nick_color(thread_id)
else:
return config.color_thread_suffix
def sha1_hex(s):
- return str(hashlib.sha1(s.encode('utf-8')).hexdigest())
+ return str(hashlib.sha1(s.encode("utf-8")).hexdigest())
def get_functions_with_prefix(prefix):
- return {name[len(prefix):]: ref for name, ref in globals().items()
- if name.startswith(prefix)}
+ return {
+ name[len(prefix) :]: ref
+ for name, ref in globals().items()
+ if name.startswith(prefix)
+ }
def handle_socket_error(exception, team, caller_name):
- if not (isinstance(exception, WebSocketConnectionClosedException) or
- exception.errno in (errno.EPIPE, errno.ECONNRESET, errno.ETIMEDOUT)):
+ if not (
+ isinstance(exception, WebSocketConnectionClosedException)
+ or exception.errno in (errno.EPIPE, errno.ECONNRESET, errno.ETIMEDOUT)
+ ):
raise
- w.prnt(team.channel_buffer,
- 'Lost connection to slack team {} (on {}), reconnecting.'.format(
- team.domain, caller_name))
- dbg('Socket failed on {} with exception:\n{}'.format(
- caller_name, format_exc_tb()), level=5)
+ w.prnt(
+ team.channel_buffer,
+ "Lost connection to slack team {} (on {}), reconnecting.".format(
+ team.domain, caller_name
+ ),
+ )
+ dbg(
+ "Socket failed on {} with exception:\n{}".format(caller_name, format_exc_tb()),
+ level=5,
+ )
team.set_disconnected()
-MESSAGE_ID_REGEX_STRING = r'(?P<msg_id>\d+|\$[0-9a-fA-F]{3,})'
-REACTION_PREFIX_REGEX_STRING = r'{}?(?P<reaction_change>\+|-)'.format(MESSAGE_ID_REGEX_STRING)
+MESSAGE_ID_REGEX_STRING = r"(?P<msg_id>\d+|\$[0-9a-fA-F]{3,})"
+REACTION_PREFIX_REGEX_STRING = r"{}?(?P<reaction_change>\+|-)".format(
+ MESSAGE_ID_REGEX_STRING
+)
-EMOJI_CHAR_REGEX_STRING = '(?P<emoji_char>[\U00000080-\U0010ffff]+)'
-EMOJI_NAME_REGEX_STRING = ':(?P<emoji_name>[a-z0-9_+-]+):'
-EMOJI_CHAR_OR_NAME_REGEX_STRING = '({}|{})'.format(EMOJI_CHAR_REGEX_STRING, EMOJI_NAME_REGEX_STRING)
+EMOJI_CHAR_REGEX_STRING = "(?P<emoji_char>[\U00000080-\U0010ffff]+)"
+EMOJI_NAME_REGEX_STRING = ":(?P<emoji_name>[a-z0-9_+-]+):"
+EMOJI_CHAR_OR_NAME_REGEX_STRING = "({}|{})".format(
+ EMOJI_CHAR_REGEX_STRING, EMOJI_NAME_REGEX_STRING
+)
EMOJI_NAME_REGEX = re.compile(EMOJI_NAME_REGEX_STRING)
EMOJI_CHAR_OR_NAME_REGEX = re.compile(EMOJI_CHAR_OR_NAME_REGEX_STRING)
@@ -404,12 +448,12 @@ def regex_match_to_emoji(match, include_name=False):
full_match = match.group()
char = EMOJI.get(emoji, full_match)
if include_name and char != full_match:
- return '{} ({})'.format(char, full_match)
+ return "{} ({})".format(char, full_match)
return char
def replace_string_with_emoji(text):
- if config.render_emoji_as_string == 'both':
+ if config.render_emoji_as_string == "both":
return EMOJI_NAME_REGEX.sub(
partial(regex_match_to_emoji, include_name=True),
text,
@@ -430,8 +474,8 @@ def replace_emoji_with_string(text):
###### New central Event router
-class EventRouter(object):
+class EventRouter(object):
def __init__(self):
"""
complete
@@ -483,19 +527,19 @@ class EventRouter(object):
if team:
team_subdomain = team.subdomain
else:
- team_json = message_json.get('team')
+ team_json = message_json.get("team")
if team_json:
- team_subdomain = team_json.get('domain')
+ team_subdomain = team_json.get("domain")
else:
- team_subdomain = 'unknown_team'
+ team_subdomain = "unknown_team"
directory = "{}/{}".format(RECORD_DIR, team_subdomain)
if subdir:
directory = "{}/{}".format(directory, subdir)
if not os.path.exists(directory):
os.makedirs(directory)
- mtype = message_json.get(file_name_field, 'unknown')
- f = open('{}/{}-{}.json'.format(directory, now, mtype), 'w')
+ mtype = message_json.get(file_name_field, "unknown")
+ f = open("{}/{}-{}.json".format(directory, now, mtype), "w")
f.write("{}".format(json.dumps(message_json)))
f.close()
@@ -505,7 +549,9 @@ class EventRouter(object):
weechat's "callback_data" has a limited size and weechat will crash if you exceed
this size.
"""
- identifier = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(40))
+ identifier = "".join(
+ random.choice(string.ascii_uppercase + string.digits) for _ in range(40)
+ )
self.context[identifier] = data
dbg("stored context {} {} ".format(identifier, data.url))
return identifier
@@ -549,10 +595,17 @@ class EventRouter(object):
for team in self.teams.values():
time_since_last_ping = time.time() - team.last_ping_time
time_since_last_pong = time.time() - team.last_pong_time
- if team.connected and time_since_last_ping < 5 and time_since_last_pong > 30:
- w.prnt(team.channel_buffer,
- 'Lost connection to slack team {} (no pong), reconnecting.'.format(
- team.domain))
+ if (
+ team.connected
+ and time_since_last_ping < 5
+ and time_since_last_pong > 30
+ ):
+ w.prnt(
+ team.channel_buffer,
+ "Lost connection to slack team {} (no pong), reconnecting.".format(
+ team.domain
+ ),
+ )
team.set_disconnected()
if not team.connected:
team.connect(reconnect=True)
@@ -576,7 +629,7 @@ class EventRouter(object):
# No more data to read at this time.
return w.WEECHAT_RC_OK
except (WebSocketConnectionClosedException, socket.error) as e:
- handle_socket_error(e, team, 'receive')
+ handle_socket_error(e, team, "receive")
return w.WEECHAT_RC_OK
if opcode == ABNF.OPCODE_PONG:
@@ -585,9 +638,9 @@ class EventRouter(object):
elif opcode != ABNF.OPCODE_TEXT:
return w.WEECHAT_RC_OK
- message_json = json.loads(data.decode('utf-8'))
+ message_json = json.loads(data.decode("utf-8"))
if self.recording:
- self.record_event(message_json, team, 'type', 'websocket')
+ self.record_event(message_json, team, "type", "websocket")
message_json["wee_slack_metadata_team"] = team
self.receive(message_json)
return w.WEECHAT_RC_OK
@@ -603,21 +656,32 @@ class EventRouter(object):
where the request originated and route properly.
"""
request_metadata = self.retrieve_context(data)
- dbg("RECEIVED CALLBACK with request of {} id of {} and code {} of length {}".format(request_metadata.request, request_metadata.response_id, return_code, len(out)))
+ dbg(
+ "RECEIVED CALLBACK with request of {} id of {} and code {} of length {}".format(
+ request_metadata.request,
+ request_metadata.response_id,
+ return_code,
+ len(out),
+ )
+ )
if return_code == 0:
if len(out) > 0:
if request_metadata.response_id not in self.reply_buffer:
self.reply_buffer[request_metadata.response_id] = StringIO()
self.reply_buffer[request_metadata.response_id].write(out)
try:
- j = json.loads(self.reply_buffer[request_metadata.response_id].getvalue())
+ j = json.loads(
+ self.reply_buffer[request_metadata.response_id].getvalue()
+ )
except:
pass
# dbg("Incomplete json, awaiting more", True)
try:
j["wee_slack_process_method"] = request_metadata.request_normalized
if self.recording:
- self.record_event(j, request_metadata.team, 'wee_slack_process_method', 'http')
+ self.record_event(
+ j, request_metadata.team, "wee_slack_process_method", "http"
+ )
j["wee_slack_request_metadata"] = request_metadata
self.reply_buffer.pop(request_metadata.response_id)
self.receive(j)
@@ -637,14 +701,30 @@ class EventRouter(object):
else:
self.reply_buffer.pop(request_metadata.response_id, None)
self.delete_context(data)
- if request_metadata.request.startswith('rtm.'):
- retry_text = ('retrying' if request_metadata.should_try() else
- 'will not retry after too many failed attempts')
- w.prnt('', ('Failed connecting to slack team with token {}, {}. ' +
- 'If this persists, try increasing slack_timeout. Error (code {}): {}')
- .format(token_for_print(request_metadata.token), retry_text, return_code, err))
- dbg('rtm.start failed with return_code {}. stack:\n{}'
- .format(return_code, ''.join(traceback.format_stack())), level=5)
+ if request_metadata.request.startswith("rtm."):
+ retry_text = (
+ "retrying"
+ if request_metadata.should_try()
+ else "will not retry after too many failed attempts"
+ )
+ w.prnt(
+ "",
+ (
+ "Failed connecting to slack team with token {}, {}. "
+ + "If this persists, try increasing slack_timeout. Error (code {}): {}"
+ ).format(
+ token_for_print(request_metadata.token),
+ retry_text,
+ return_code,
+ err,
+ ),
+ )
+ dbg(
+ "rtm.start failed with return_code {}. stack:\n{}".format(
+ return_code, "".join(traceback.format_stack())
+ ),
+ level=5,
+ )
self.receive(request_metadata)
return w.WEECHAT_RC_OK
@@ -670,13 +750,17 @@ class EventRouter(object):
wanted_interval = 100
if len(self.slow_queue) > 0 or len(self.queue) > 0:
wanted_interval = 10
- if self.handle_next_hook is None or wanted_interval != self.handle_next_hook_interval:
+ if (
+ self.handle_next_hook is None
+ or wanted_interval != self.handle_next_hook_interval
+ ):
if self.handle_next_hook:
w.unhook(self.handle_next_hook)
- self.handle_next_hook = w.hook_timer(wanted_interval, 0, 0, "handle_next", "")
+ self.handle_next_hook = w.hook_timer(
+ wanted_interval, 0, 0, "handle_next", ""
+ )
self.handle_next_hook_interval = wanted_interval
-
if len(self.slow_queue) > 0 and ((self.slow_queue_timer + 1) < time.time()):
dbg("from slow queue", 0)
self.queue.append(self.slow_queue.pop())
@@ -721,14 +805,23 @@ class EventRouter(object):
if team:
if "channel" in j:
- channel_id = j["channel"]["id"] if type(j["channel"]) == dict else j["channel"]
+ channel_id = (
+ j["channel"]["id"]
+ if type(j["channel"]) == dict
+ else j["channel"]
+ )
channel = team.channels.get(channel_id, channel)
if "user" in j:
- user_id = j["user"]["id"] if type(j["user"]) == dict else j["user"]
- metadata['user'] = team.users.get(user_id)
+ user_id = (
+ j["user"]["id"] if type(j["user"]) == dict else j["user"]
+ )
+ metadata["user"] = team.users.get(user_id)
dbg("running {}".format(function_name))
- if function_name.startswith("local_") and function_name in self.local_proc:
+ if (
+ function_name.startswith("local_")
+ and function_name in self.local_proc
+ ):
self.local_proc[function_name](j, self, team, channel, metadata)
elif function_name in self.proc:
self.proc[function_name](j, self, team, channel, metadata)
@@ -797,6 +890,7 @@ class WeechatController(object):
def set_previous_buffer(self, data):
self.previous_buffer = data
+
###### New Local Processors
@@ -807,14 +901,25 @@ def local_process_async_slack_api_request(request, event_router):
DEBUGGING!!! The context here cannot be very large. Weechat will crash.
"""
if not event_router.shutting_down:
- weechat_request = 'url:{}'.format(request.request_string())
- weechat_request += '&nonce={}'.format(''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(4)))
- params = {'useragent': 'wee_slack {}'.format(SCRIPT_VERSION)}
+ weechat_request = "url:{}".format(request.request_string())
+ weechat_request += "&nonce={}".format(
+ "".join(
+ random.choice(string.ascii_uppercase + string.digits) for _ in range(4)
+ )
+ )
+ params = {"useragent": "wee_slack {}".format(SCRIPT_VERSION)}
request.tried()
context = event_router.store_context(request)
# TODO: let flashcode know about this bug - i have to 'clear' the hashtable or retry requests fail
- w.hook_process_hashtable('url:', params, config.slack_timeout, "", context)
- w.hook_process_hashtable(weechat_request, params, config.slack_timeout, "receive_httprequest_callback", context)
+ w.hook_process_hashtable("url:", params, config.slack_timeout, "", context)
+ w.hook_process_hashtable(
+ weechat_request,
+ params,
+ config.slack_timeout,
+ "receive_httprequest_callback",
+ context,
+ )
+
###### New Callbacks
@@ -827,7 +932,7 @@ def ws_ping_cb(data, remaining_calls):
team.ws.ping()
team.last_ping_time = time.time()
except (WebSocketConnectionClosedException, socket.error) as e:
- handle_socket_error(e, team, 'ping')
+ handle_socket_error(e, team, "ping")
return w.WEECHAT_RC_OK
@@ -840,14 +945,19 @@ def reconnect_callback(*args):
@utf8_decode
def buffer_renamed_cb(data, signal, current_buffer):
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
- if isinstance(channel, SlackChannelCommon) and not channel.buffer_rename_in_progress:
+ if (
+ isinstance(channel, SlackChannelCommon)
+ and not channel.buffer_rename_in_progress
+ ):
if w.buffer_get_string(channel.channel_buffer, "old_full_name"):
channel.label_full_drop_prefix = True
channel.label_full = w.buffer_get_string(channel.channel_buffer, "name")
else:
channel.label_short_drop_prefix = True
- channel.label_short = w.buffer_get_string(channel.channel_buffer, "short_name")
+ channel.label_short = w.buffer_get_string(
+ channel.channel_buffer, "short_name"
+ )
channel.rename()
return w.WEECHAT_RC_OK
@@ -871,13 +981,18 @@ def buffer_input_callback(signal, buffer_ptr, data):
sending messages.
"""
if weechat_version < 0x2090000:
- data = data.replace('\r', '\n')
+ data = data.replace("\r", "\n")
eventrouter = eval(signal)
channel = eventrouter.weechat_controller.get_channel_from_buffer_ptr(buffer_ptr)
if not channel:
return w.WEECHAT_RC_ERROR
- reaction = re.match(r"{}{}\s*$".format(REACTION_PREFIX_REGEX_STRING, EMOJI_CHAR_OR_NAME_REGEX_STRING), data)
+ reaction = re.match(
+ r"{}{}\s*$".format(
+ REACTION_PREFIX_REGEX_STRING, EMOJI_CHAR_OR_NAME_REGEX_STRING
+ ),
+ data,
+ )
substitute = re.match("{}?s/".format(MESSAGE_ID_REGEX_STRING), data)
if reaction:
emoji = reaction.group("emoji_char") or reaction.group("emoji_name")
@@ -887,18 +1002,22 @@ def buffer_input_callback(signal, buffer_ptr, data):
channel.send_remove_reaction(reaction.group("msg_id"), emoji)
elif substitute:
try:
- old, new, flags = re.split(r'(?<!\\)/', data)[1:]
+ old, new, flags = re.split(r"(?<!\\)/", data)[1:]
except ValueError:
- print_error('Incomplete regex for changing a message, '
- 'it should be in the form s/old text/new text/')
+ print_error(
+ "Incomplete regex for changing a message, "
+ "it should be in the form s/old text/new text/"
+ )
else:
# Replacement string in re.sub() is a string, not a regex, so get
# rid of escapes.
- new = new.replace(r'\/', '/')
- old = old.replace(r'\/', '/')
- channel.edit_nth_previous_message(substitute.group("msg_id"), old, new, flags)
+ new = new.replace(r"\/", "/")
+ old = old.replace(r"\/", "/")
+ channel.edit_nth_previous_message(
+ substitute.group("msg_id"), old, new, flags
+ )
else:
- if data.startswith(('//', ' ')):
+ if data.startswith(("//", " ")):
data = data[1:]
channel.send_message(data)
# this is probably wrong channel.mark_read(update_remote=True, force=True)
@@ -913,7 +1032,7 @@ def buffer_input_callback(signal, buffer_ptr, data):
def input_text_for_buffer_cb(data, modifier, current_buffer, string):
if current_buffer not in EVENTROUTER.weechat_controller.buffers:
return string
- return re.sub('\r?\n', '\r', decode_from_utf8(string))
+ return re.sub("\r?\n", "\r", decode_from_utf8(string))
@utf8_decode
@@ -929,7 +1048,9 @@ def buffer_switch_callback(data, signal, current_buffer):
if prev:
prev.mark_read()
- new_channel = EVENTROUTER.weechat_controller.get_channel_from_buffer_ptr(current_buffer)
+ new_channel = EVENTROUTER.weechat_controller.get_channel_from_buffer_ptr(
+ current_buffer
+ )
if new_channel:
if not new_channel.got_history or new_channel.history_needs_update:
new_channel.get_history()
@@ -1002,7 +1123,7 @@ def typing_bar_item_cb(data, item, current_window, current_buffer, extra_info):
if current_channel:
# this try is mostly becuase server buffers don't implement is_someone_typing
try:
- if current_channel.type != 'im' and current_channel.is_someone_typing():
+ if current_channel.type != "im" and current_channel.is_someone_typing():
typers += current_channel.get_typing_list()
except:
pass
@@ -1027,16 +1148,16 @@ def typing_bar_item_cb(data, item, current_window, current_buffer, extra_info):
def away_bar_item_cb(data, item, current_window, current_buffer, extra_info):
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if not channel:
- return ''
+ return ""
if channel.team.is_user_present(channel.team.myidentifier):
- return ''
+ return ""
else:
- away_color = w.config_string(w.config_get('weechat.color.item_away'))
- if channel.team.my_manual_presence == 'away':
- return colorize_string(away_color, 'manual away')
+ away_color = w.config_string(w.config_get("weechat.color.item_away"))
+ if channel.team.my_manual_presence == "away":
+ return colorize_string(away_color, "manual away")
else:
- return colorize_string(away_color, 'auto away')
+ return colorize_string(away_color, "auto away")
@utf8_decode
@@ -1045,21 +1166,40 @@ def channel_completion_cb(data, completion_item, current_buffer, completion):
Adds all channels on all teams to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
- should_include_channel = lambda channel: channel.active and channel.type in ['channel', 'group', 'private', 'shared']
+ should_include_channel = lambda channel: channel.active and channel.type in [
+ "channel",
+ "group",
+ "private",
+ "shared",
+ ]
- other_teams = [team for team in EVENTROUTER.teams.values() if not current_channel or team != current_channel.team]
+ other_teams = [
+ team
+ for team in EVENTROUTER.teams.values()
+ if not current_channel or team != current_channel.team
+ ]
for team in other_teams:
for channel in team.channels.values():
if should_include_channel(channel):
- w.hook_completion_list_add(completion, channel.name, 0, w.WEECHAT_LIST_POS_SORT)
+ w.hook_completion_list_add(
+ completion, channel.name, 0, w.WEECHAT_LIST_POS_SORT
+ )
if current_channel:
- for channel in sorted(current_channel.team.channels.values(), key=lambda channel: channel.name, reverse=True):
+ for channel in sorted(
+ current_channel.team.channels.values(),
+ key=lambda channel: channel.name,
+ reverse=True,
+ ):
if should_include_channel(channel):
- w.hook_completion_list_add(completion, channel.name, 0, w.WEECHAT_LIST_POS_BEGINNING)
+ w.hook_completion_list_add(
+ completion, channel.name, 0, w.WEECHAT_LIST_POS_BEGINNING
+ )
if should_include_channel(current_channel):
- w.hook_completion_list_add(completion, current_channel.name, 0, w.WEECHAT_LIST_POS_BEGINNING)
+ w.hook_completion_list_add(
+ completion, current_channel.name, 0, w.WEECHAT_LIST_POS_BEGINNING
+ )
return w.WEECHAT_RC_OK
@@ -1070,8 +1210,10 @@ def dm_completion_cb(data, completion_item, current_buffer, completion):
"""
for team in EVENTROUTER.teams.values():
for channel in team.channels.values():
- if channel.active and channel.type in ['im', 'mpim']:
- w.hook_completion_list_add(completion, channel.name, 0, w.WEECHAT_LIST_POS_SORT)
+ if channel.active and channel.type in ["im", "mpim"]:
+ w.hook_completion_list_add(
+ completion, channel.name, 0, w.WEECHAT_LIST_POS_SORT
+ )
return w.WEECHAT_RC_OK
@@ -1085,7 +1227,7 @@ def nick_completion_cb(data, completion_item, current_buffer, completion):
return w.WEECHAT_RC_OK
base_command = w.hook_completion_get_string(completion, "base_command")
- if base_command in ['invite', 'msg', 'query', 'whois']:
+ if base_command in ["invite", "msg", "query", "whois"]:
members = current_channel.team.members
else:
members = current_channel.members
@@ -1093,8 +1235,12 @@ def nick_completion_cb(data, completion_item, current_buffer, completion):
for member in members:
user = current_channel.team.users.get(member)
if user and not user.deleted:
- w.hook_completion_list_add(completion, user.name, 1, w.WEECHAT_LIST_POS_SORT)
- w.hook_completion_list_add(completion, "@" + user.name, 1, w.WEECHAT_LIST_POS_SORT)
+ w.hook_completion_list_add(
+ completion, user.name, 1, w.WEECHAT_LIST_POS_SORT
+ )
+ w.hook_completion_list_add(
+ completion, "@" + user.name, 1, w.WEECHAT_LIST_POS_SORT
+ )
return w.WEECHAT_RC_OK
@@ -1112,7 +1258,9 @@ def emoji_completion_cb(data, completion_item, current_buffer, completion):
prefix = reaction.group(0) if reaction else ":"
for emoji in current_channel.team.emoji_completions:
- w.hook_completion_list_add(completion, prefix + emoji + ":", 0, w.WEECHAT_LIST_POS_SORT)
+ w.hook_completion_list_add(
+ completion, prefix + emoji + ":", 0, w.WEECHAT_LIST_POS_SORT
+ )
return w.WEECHAT_RC_OK
@@ -1122,14 +1270,18 @@ def thread_completion_cb(data, completion_item, current_buffer, completion):
Adds all $-prefixed thread ids to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
- if current_channel is None or not hasattr(current_channel, 'hashed_messages'):
+ if current_channel is None or not hasattr(current_channel, "hashed_messages"):
return w.WEECHAT_RC_OK
- threads = (x for x in current_channel.hashed_messages.items() if isinstance(x[0], str))
+ threads = (
+ x for x in current_channel.hashed_messages.items() if isinstance(x[0], str)
+ )
for thread_id, message_ts in sorted(threads, key=lambda item: item[1]):
message = current_channel.messages.get(message_ts)
if message and message.number_of_replies():
- w.hook_completion_list_add(completion, "$" + thread_id, 0, w.WEECHAT_LIST_POS_BEGINNING)
+ w.hook_completion_list_add(
+ completion, "$" + thread_id, 0, w.WEECHAT_LIST_POS_BEGINNING
+ )
return w.WEECHAT_RC_OK
@@ -1144,8 +1296,8 @@ def topic_completion_cb(data, completion_item, current_buffer, completion):
topic = current_channel.render_topic()
channel_names = [channel.name for channel in current_channel.team.channels.values()]
- if topic.split(' ', 1)[0] in channel_names:
- topic = '{} {}'.format(current_channel.name, topic)
+ if topic.split(" ", 1)[0] in channel_names:
+ topic = "{} {}".format(current_channel.name, topic)
w.hook_completion_list_add(completion, topic, 0, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
@@ -1160,7 +1312,9 @@ def usergroups_completion_cb(data, completion_item, current_buffer, completion):
if current_channel is None:
return w.WEECHAT_RC_OK
- subteam_handles = [subteam.handle for subteam in current_channel.team.subteams.values()]
+ subteam_handles = [
+ subteam.handle for subteam in current_channel.team.subteams.values()
+ ]
for group in subteam_handles + ["@channel", "@everyone", "@here"]:
w.hook_completion_list_add(completion, group, 1, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
@@ -1174,7 +1328,11 @@ def complete_next_cb(data, current_buffer, command):
thing
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
- if not hasattr(current_channel, 'members') or current_channel is None or current_channel.members is None:
+ if (
+ not hasattr(current_channel, "members")
+ or current_channel is None
+ or current_channel.members is None
+ ):
return w.WEECHAT_RC_OK
line_input = w.buffer_get_string(current_buffer, "input")
@@ -1184,12 +1342,16 @@ def complete_next_cb(data, current_buffer, command):
word_start = 0
word_end = input_length
# If we're on a non-word, look left for something to complete
- while current_pos >= 0 and line_input[current_pos] != '@' and not line_input[current_pos].isalnum():
+ while (
+ current_pos >= 0
+ and line_input[current_pos] != "@"
+ and not line_input[current_pos].isalnum()
+ ):
current_pos = current_pos - 1
if current_pos < 0:
current_pos = 0
for l in range(current_pos, 0, -1):
- if line_input[l] != '@' and not line_input[l].isalnum():
+ if line_input[l] != "@" and not line_input[l].isalnum():
word_start = l + 1
break
for l in range(current_pos, input_length):
@@ -1203,8 +1365,16 @@ def complete_next_cb(data, current_buffer, command):
if user and user.name == word:
# Here, we cheat. Insert a @ in front and rely in the @
# nicks being in the completion list
- w.buffer_set(current_buffer, "input", line_input[:word_start] + "@" + line_input[word_start:])
- w.buffer_set(current_buffer, "input_pos", str(w.buffer_get_integer(current_buffer, "input_pos") + 1))
+ w.buffer_set(
+ current_buffer,
+ "input",
+ line_input[:word_start] + "@" + line_input[word_start:],
+ )
+ w.buffer_set(
+ current_buffer,
+ "input_pos",
+ str(w.buffer_get_integer(current_buffer, "input_pos") + 1),
+ )
return w.WEECHAT_RC_OK_EAT
return w.WEECHAT_RC_OK
@@ -1221,12 +1391,13 @@ def stop_talking_to_slack():
which triggers leaving the channel because of how close
buffer is handled
"""
- if 'EVENTROUTER' in globals():
+ if "EVENTROUTER" in globals():
EVENTROUTER.shutdown()
for team in EVENTROUTER.teams.values():
team.ws.shutdown()
return w.WEECHAT_RC_OK
+
##### New Classes
@@ -1236,7 +1407,16 @@ class SlackRequest(object):
makes a SHA of the requst url and current time so we can re-tag this on the way back through.
"""
- def __init__(self, team, request, post_data=None, channel=None, metadata=None, retries=3, token=None):
+ def __init__(
+ self,
+ team,
+ request,
+ post_data=None,
+ channel=None,
+ metadata=None,
+ retries=3,
+ token=None,
+ ):
if team is None and token is None:
raise ValueError("Both team and token can't be None")
self.team = team
@@ -1248,17 +1428,28 @@ class SlackRequest(object):
self.token = token if token else team.token
self.tries = 0
self.start_time = time.time()
- self.request_normalized = re.sub(r'\W+', '', request)
- self.domain = 'api.slack.com'
- self.post_data['token'] = self.token
- self.url = 'https://{}/api/{}?{}'.format(self.domain, self.request, urlencode(encode_to_utf8(self.post_data)))
- self.params = {'useragent': 'wee_slack {}'.format(SCRIPT_VERSION)}
- self.response_id = sha1_hex('{}{}'.format(self.url, self.start_time))
+ self.request_normalized = re.sub(r"\W+", "", request)
+ self.domain = "api.slack.com"
+ self.post_data["token"] = self.token
+ self.url = "https://{}/api/{}?{}".format(
+ self.domain, self.request, urlencode(encode_to_utf8(self.post_data))
+ )
+ self.params = {"useragent": "wee_slack {}".format(SCRIPT_VERSION)}
+ self.response_id = sha1_hex("{}{}".format(self.url, self.start_time))
def __repr__(self):
- return ("SlackRequest(team={}, request='{}', post_data={}, retries={}, token='{}', "
- "tries={}, start_time={})").format(self.team, self.request, self.post_data,
- self.retries, token_for_print(self.token), self.tries, self.start_time)
+ return (
+ "SlackRequest(team={}, request='{}', post_data={}, retries={}, token='{}', "
+ "tries={}, start_time={})"
+ ).format(
+ self.team,
+ self.request,
+ self.post_data,
+ self.retries,
+ token_for_print(self.token),
+ self.tries,
+ self.start_time,
+ )
def request_string(self):
return "{}".format(self.url)
@@ -1271,27 +1462,27 @@ class SlackRequest(object):
return self.tries < self.retries
def retry_ready(self):
- return (self.start_time + (self.tries**2)) < time.time()
+ return (self.start_time + (self.tries ** 2)) < time.time()
class SlackSubteam(object):
- """
- Represents a slack group or subteam
- """
+ """
+ Represents a slack group or subteam
+ """
- def __init__(self, originating_team_id, is_member, **kwargs):
- self.handle = '@{}'.format(kwargs['handle'])
- self.identifier = kwargs['id']
- self.name = kwargs['name']
- self.description = kwargs.get('description')
- self.team_id = originating_team_id
- self.is_member = is_member
+ def __init__(self, originating_team_id, is_member, **kwargs):
+ self.handle = "@{}".format(kwargs["handle"])
+ self.identifier = kwargs["id"]
+ self.name = kwargs["name"]
+ self.description = kwargs.get("description")
+ self.team_id = originating_team_id
+ self.is_member = is_member
- def __repr__(self):
- return "Name:{} Identifier:{}".format(self.name, self.identifier)
+ def __repr__(self):
+ return "Name:{} Identifier:{}".format(self.name, self.identifier)
- def __eq__(self, compare_str):
- return compare_str == self.identifier
+ def __eq__(self, compare_str):
+ return compare_str == self.identifier
class SlackTeam(object):
@@ -1300,7 +1491,22 @@ class SlackTeam(object):
Team object under which users and channels live.. Does lots.
"""
- def __init__(self, eventrouter, token, team_hash, websocket_url, team_info, subteams, nick, myidentifier, my_manual_presence, users, bots, channels, **kwargs):
+ def __init__(
+ self,
+ eventrouter,
+ token,
+ team_hash,
+ websocket_url,
+ team_info,
+ subteams,
+ nick,
+ myidentifier,
+ my_manual_presence,
+ users,
+ bots,
+ channels,
+ **kwargs
+ ):
self.slack_api_translator = copy.deepcopy(SLACK_API_TRANSLATOR)
self.identifier = team_info["id"]
self.type = "team"
@@ -1339,13 +1545,15 @@ class SlackTeam(object):
self.got_history = True
self.history_needs_update = False
self.create_buffer()
- self.set_muted_channels(kwargs.get('muted_channels', ""))
- self.set_highlight_words(kwargs.get('highlight_words', ""))
+ self.set_muted_channels(kwargs.get("muted_channels", ""))
+ self.set_highlight_words(kwargs.get("highlight_words", ""))
for c in self.channels.keys():
channels[c].set_related_server(self)
channels[c].check_should_open()
# Last step is to make sure my nickname is the set color
- self.users[self.myidentifier].force_color(w.config_string(w.config_get('weechat.color.chat_nick_self')))
+ self.users[self.myidentifier].force_color(
+ w.config_string(w.config_get("weechat.color.chat_nick_self"))
+ )
# This highlight step must happen after we have set related server
self.load_emoji_completions()
@@ -1353,7 +1561,11 @@ class SlackTeam(object):
return "domain={} nick={}".format(self.subdomain, self.nick)
def __eq__(self, compare_str):
- return compare_str == self.token or compare_str == self.domain or compare_str == self.subdomain
+ return (
+ compare_str == self.token
+ or compare_str == self.domain
+ or compare_str == self.subdomain
+ )
@property
def members(self):
@@ -1383,10 +1595,14 @@ class SlackTeam(object):
def create_buffer(self):
if not self.channel_buffer:
- self.channel_buffer = w.buffer_new(self.name, "buffer_input_callback", "EVENTROUTER", "", "")
- self.eventrouter.weechat_controller.register_buffer(self.channel_buffer, self)
+ self.channel_buffer = w.buffer_new(
+ self.name, "buffer_input_callback", "EVENTROUTER", "", ""
+ )
+ self.eventrouter.weechat_controller.register_buffer(
+ self.channel_buffer, self
+ )
w.buffer_set(self.channel_buffer, "input_multiline", "1")
- w.buffer_set(self.channel_buffer, "localvar_set_type", 'server')
+ w.buffer_set(self.channel_buffer, "localvar_set_type", "server")
w.buffer_set(self.channel_buffer, "localvar_set_slack_type", self.type)
w.buffer_set(self.channel_buffer, "localvar_set_nick", self.nick)
w.buffer_set(self.channel_buffer, "localvar_set_server", self.name)
@@ -1394,8 +1610,8 @@ class SlackTeam(object):
def buffer_merge(self, config_value=None):
if not config_value:
- config_value = w.config_string(w.config_get('irc.look.server_buffer'))
- if config_value == 'merge_with_core':
+ config_value = w.config_string(w.config_get("irc.look.server_buffer"))
+ if config_value == "merge_with_core":
w.buffer_merge(self.channel_buffer, w.buffer_search_main())
else:
w.buffer_unmerge(self.channel_buffer, 0)
@@ -1404,13 +1620,13 @@ class SlackTeam(object):
pass
def set_muted_channels(self, muted_str):
- self.muted_channels = {x for x in muted_str.split(',') if x}
+ self.muted_channels = {x for x in muted_str.split(",") if x}
for channel in self.channels.values():
channel.set_highlights()
channel.rename()
def set_highlight_words(self, highlight_str):
- self.highlight_words = {x for x in highlight_str.split(',') if x}
+ self.highlight_words = {x for x in highlight_str.split(",") if x}
for channel in self.channels.values():
channel.set_highlights()
@@ -1428,7 +1644,8 @@ class SlackTeam(object):
def find_channel_by_members(self, members, channel_type=None):
for channel in self.channels.values():
if channel.members == members and (
- channel_type is None or channel.type == channel_type):
+ channel_type is None or channel.type == channel_type
+ ):
return channel
def get_channel_map(self):
@@ -1449,7 +1666,7 @@ class SlackTeam(object):
def is_user_present(self, user_id):
user = self.users.get(user_id)
- if user and user.presence == 'active':
+ if user and user.presence == "active":
return True
else:
return False
@@ -1466,16 +1683,39 @@ class SlackTeam(object):
proxy = ProxyWrapper()
timeout = config.slack_timeout / 1000
if proxy.has_proxy == True:
- ws = create_connection(self.ws_url, timeout=timeout, sslopt=sslopt_ca_certs, http_proxy_host=proxy.proxy_address, http_proxy_port=proxy.proxy_port, http_proxy_auth=(proxy.proxy_user, proxy.proxy_password))
+ ws = create_connection(
+ self.ws_url,
+ timeout=timeout,
+ sslopt=sslopt_ca_certs,
+ http_proxy_host=proxy.proxy_address,
+ http_proxy_port=proxy.proxy_port,
+ http_proxy_auth=(proxy.proxy_user, proxy.proxy_password),
+ )
else:
- ws = create_connection(self.ws_url, timeout=timeout, sslopt=sslopt_ca_certs)
-
- self.hook = w.hook_fd(ws.sock.fileno(), 1, 0, 0, "receive_ws_callback", self.get_team_hash())
+ ws = create_connection(
+ self.ws_url, timeout=timeout, sslopt=sslopt_ca_certs
+ )
+
+ self.hook = w.hook_fd(
+ ws.sock.fileno(),
+ 1,
+ 0,
+ 0,
+ "receive_ws_callback",
+ self.get_team_hash(),
+ )
ws.sock.setblocking(0)
except:
- w.prnt(self.channel_buffer,
- 'Failed connecting to slack team {}, retrying.'.format(self.domain))
- dbg('connect failed with exception:\n{}'.format(format_exc_tb()), level=5)
+ w.prnt(
+ self.channel_buffer,
+ "Failed connecting to slack team {}, retrying.".format(
+ self.domain
+ ),
+ )
+ dbg(
+ "connect failed with exception:\n{}".format(format_exc_tb()),
+ level=5,
+ )
return False
finally:
self.connecting_ws = False
@@ -1486,15 +1726,20 @@ class SlackTeam(object):
# The fast reconnect failed, so start over-ish
for chan in self.channels:
self.channels[chan].history_needs_update = True
- s = initiate_connection(self.token, retries=999, team=self, reconnect=reconnect)
+ s = initiate_connection(
+ self.token, retries=999, team=self, reconnect=reconnect
+ )
self.eventrouter.receive(s)
self.connecting_rtm = True
def set_connected(self):
self.connected = True
self.last_pong_time = time.time()
- self.buffer_prnt('Connected to Slack team {} ({}) with username {}'.format(
- self.team_info["name"], self.domain, self.nick))
+ self.buffer_prnt(
+ "Connected to Slack team {} ({}) with username {}".format(
+ self.team_info["name"], self.domain, self.nick
+ )
+ )
dbg("connected to {}".format(self.domain))
if config.background_load_all_history:
@@ -1502,8 +1747,13 @@ class SlackTeam(object):
if channel.channel_buffer:
channel.get_history(slow_queue=True)
else:
- current_channel = self.eventrouter.weechat_controller.buffers.get(w.current_buffer())
- if isinstance(current_channel, SlackChannelCommon) and current_channel.team == self:
+ current_channel = self.eventrouter.weechat_controller.buffers.get(
+ w.current_buffer()
+ )
+ if (
+ isinstance(current_channel, SlackChannelCommon)
+ and current_channel.team == self
+ ):
current_channel.get_history(slow_queue=True)
def set_disconnected(self):
@@ -1526,7 +1776,7 @@ class SlackTeam(object):
self.ws.send(encode_to_utf8(message))
dbg("Sent {}...".format(message[:100]))
except (WebSocketConnectionClosedException, socket.error) as e:
- handle_socket_error(e, self, 'send')
+ handle_socket_error(e, self, "send")
def update_member_presence(self, user, presence):
user.presence = presence
@@ -1545,10 +1795,13 @@ class SlackTeam(object):
users = list(self.users.keys())[:750]
if self.myidentifier not in users:
users.append(self.myidentifier)
- self.send_to_websocket({
- "type": "presence_sub",
- "ids": users,
- }, expect_reply=False)
+ self.send_to_websocket(
+ {
+ "type": "presence_sub",
+ "ids": users,
+ },
+ expect_reply=False,
+ )
class SlackChannelCommon(object):
@@ -1559,7 +1812,9 @@ class SlackChannelCommon(object):
self.label_short = None
self.buffer_rename_in_progress = False
- def prnt_message(self, message, history_message=False, no_log=False, force_render=False):
+ def prnt_message(
+ self, message, history_message=False, no_log=False, force_render=False
+ ):
text = self.render(message, force_render)
thread_channel = isinstance(self, SlackThreadChannel)
@@ -1593,16 +1848,27 @@ class SlackChannelCommon(object):
else:
return
- self.buffer_prnt(prefix, text, message.ts, tagset=tagset,
- tag_nick=message.sender_plain, history_message=history_message,
- no_log=no_log, extra_tags=extra_tags)
+ self.buffer_prnt(
+ prefix,
+ text,
+ message.ts,
+ tagset=tagset,
+ tag_nick=message.sender_plain,
+ history_message=history_message,
+ no_log=no_log,
+ extra_tags=extra_tags,
+ )
def print_getting_history(self):
if self.channel_buffer:
ts = SlackTS()
w.buffer_set(self.channel_buffer, "print_hooks_enabled", "0")
- w.prnt_date_tags(self.channel_buffer, ts.major,
- tag(ts, backlog=True, no_log=True), '\tgetting channel history...')
+ w.prnt_date_tags(
+ self.channel_buffer,
+ ts.major,
+ tag(ts, backlog=True, no_log=True),
+ "\tgetting channel history...",
+ )
w.buffer_set(self.channel_buffer, "print_hooks_enabled", "1")
def reprint_messages(self, history_message=False, no_log=True, force_render=False):
@@ -1611,19 +1877,31 @@ class SlackChannelCommon(object):
self.last_line_from = None
for message in self.visible_messages.values():
self.prnt_message(message, history_message, no_log, force_render)
- if (self.identifier in self.pending_history_requests or
- config.thread_messages_in_channel and self.pending_history_requests):
+ if (
+ self.identifier in self.pending_history_requests
+ or config.thread_messages_in_channel
+ and self.pending_history_requests
+ ):
self.print_getting_history()
def send_message(self, message, subtype=None, request_dict_ext={}):
- if subtype == 'me_message':
+ if subtype == "me_message":
message = linkify_text(message, self.team, escape_characters=False)
- s = SlackRequest(self.team, "chat.meMessage", {"channel": self.identifier, "text": message}, channel=self)
+ s = SlackRequest(
+ self.team,
+ "chat.meMessage",
+ {"channel": self.identifier, "text": message},
+ channel=self,
+ )
self.eventrouter.receive(s)
else:
message = linkify_text(message, self.team)
- request = {"type": "message", "channel": self.identifier,
- "text": message, "user": self.team.myidentifier}
+ request = {
+ "type": "message",
+ "channel": self.identifier,
+ "text": message,
+ "user": self.team.myidentifier,
+ }
request.update(request_dict_ext)
self.team.send_to_websocket(request)
@@ -1647,18 +1925,28 @@ class SlackChannelCommon(object):
else:
method = "reactions.add"
- data = {"channel": self.identifier, "timestamp": message.ts, "name": reaction_name}
- s = SlackRequest(self.team, method, data, channel=self, metadata={'reaction': reaction})
+ data = {
+ "channel": self.identifier,
+ "timestamp": message.ts,
+ "name": reaction_name,
+ }
+ s = SlackRequest(
+ self.team, method, data, channel=self, metadata={"reaction": reaction}
+ )
self.eventrouter.receive(s)
def edit_nth_previous_message(self, msg_id, old, new, flags):
- message_filter = lambda message: message.user_identifier == self.team.myidentifier
+ message_filter = (
+ lambda message: message.user_identifier == self.team.myidentifier
+ )
message = self.message_from_hash_or_index(msg_id, message_filter)
if message is None:
if msg_id:
- print_error("Invalid id given, must be an existing id to one of your " +
- "messages or a number greater than 0 and less than the number " +
- "of your messages in the channel")
+ print_error(
+ "Invalid id given, must be an existing id to one of your "
+ + "messages or a number greater than 0 and less than the number "
+ + "of your messages in the channel"
+ )
else:
print_error("You don't have any messages in this channel")
return
@@ -1667,15 +1955,19 @@ class SlackChannelCommon(object):
s = SlackRequest(self.team, "chat.delete", post_data, channel=self)
self.eventrouter.receive(s)
else:
- num_replace = 0 if 'g' in flags else 1
+ num_replace = 0 if "g" in flags else 1
f = re.UNICODE
- f |= re.IGNORECASE if 'i' in flags else 0
- f |= re.MULTILINE if 'm' in flags else 0
- f |= re.DOTALL if 's' in flags else 0
+ f |= re.IGNORECASE if "i" in flags else 0
+ f |= re.MULTILINE if "m" in flags else 0
+ f |= re.DOTALL if "s" in flags else 0
old_message_text = message.message_json["text"]
new_message_text = re.sub(old, new, old_message_text, num_replace, f)
if new_message_text != old_message_text:
- post_data = {"channel": self.identifier, "ts": message.ts, "text": new_message_text}
+ post_data = {
+ "channel": self.identifier,
+ "ts": message.ts,
+ "text": new_message_text,
+ }
s = SlackRequest(self.team, "chat.update", post_data, channel=self)
self.eventrouter.receive(s)
else:
@@ -1694,14 +1986,16 @@ class SlackChannelCommon(object):
return message
def message_from_index(self, index, message_filter=None, reverse=True):
- for ts in (reversed(self.visible_messages) if reverse else self.visible_messages):
+ for ts in reversed(self.visible_messages) if reverse else self.visible_messages:
message = self.messages[ts]
if not message_filter or message_filter(message):
index -= 1
if index == 0:
return message
- def message_from_hash_or_index(self, hash_or_index=None, message_filter=None, reverse=True):
+ def message_from_hash_or_index(
+ self, hash_or_index=None, message_filter=None, reverse=True
+ ):
message = self.message_from_hash(hash_or_index, message_filter)
if not message:
if not hash_or_index:
@@ -1723,13 +2017,19 @@ class SlackChannelCommon(object):
if text:
m.change_text(text)
- if (type(m) == SlackMessage or m.subtype == "thread_broadcast"
- or config.thread_messages_in_channel):
+ if (
+ type(m) == SlackMessage
+ or m.subtype == "thread_broadcast"
+ or config.thread_messages_in_channel
+ ):
new_text = self.render(m, force=True)
modify_buffer_line(self.channel_buffer, ts, new_text)
if type(m) == SlackThreadMessage or m.thread_channel is not None:
- thread_channel = (m.parent_message.thread_channel
- if isinstance(m, SlackThreadMessage) else m.thread_channel)
+ thread_channel = (
+ m.parent_message.thread_channel
+ if isinstance(m, SlackThreadMessage)
+ else m.thread_channel
+ )
if thread_channel and thread_channel.active:
new_text = thread_channel.render(m, force=True)
modify_buffer_line(thread_channel.channel_buffer, ts, new_text)
@@ -1769,7 +2069,7 @@ class SlackChannel(SlackChannelCommon):
for key, value in kwargs.items():
setattr(self, key, value)
self.eventrouter = eventrouter
- self.team = kwargs.get('team')
+ self.team = kwargs.get("team")
self.identifier = kwargs["id"]
self.type = channel_type
self.set_name(kwargs["name"])
@@ -1787,14 +2087,18 @@ class SlackChannel(SlackChannelCommon):
self.new_messages = False
self.typing = {}
# short name relates to the localvar we change for typing indication
- self.set_members(kwargs.get('members', []))
+ self.set_members(kwargs.get("members", []))
self.unread_count_display = 0
self.last_line_from = None
self.buffer_name_needs_update = False
self.last_refresh_typing = False
def __eq__(self, compare_str):
- if compare_str == self.slack_name or compare_str == self.formatted_name() or compare_str == self.formatted_name(style="long_default"):
+ if (
+ compare_str == self.slack_name
+ or compare_str == self.formatted_name()
+ or compare_str == self.formatted_name(style="long_default")
+ ):
return True
else:
return False
@@ -1823,7 +2127,9 @@ class SlackChannel(SlackChannelCommon):
self.buffer_rename_in_progress = True
if typing is None:
typing = self.is_someone_typing()
- present = self.team.is_user_present(self.user) if self.type == "im" else None
+ present = (
+ self.team.is_user_present(self.user) if self.type == "im" else None
+ )
name = self.formatted_name("long_default", typing, present)
short_name = self.formatted_name("sidebar", typing, present)
@@ -1878,7 +2184,12 @@ class SlackChannel(SlackChannelCommon):
if self.label_short_drop_prefix:
if show_typing:
name = prepend + name[1:]
- elif self.type == "im" and present and config.show_buflist_presence and name[0] == " ":
+ elif (
+ self.type == "im"
+ and present
+ and config.show_buflist_presence
+ and name[0] == " "
+ ):
name = prepend + name[1:]
else:
name = prepend + name
@@ -1903,9 +2214,9 @@ class SlackChannel(SlackChannelCommon):
return prepend + name
def render_topic(self, fallback_to_purpose=False):
- topic = self.topic['value']
+ topic = self.topic["value"]
if not topic and fallback_to_purpose:
- topic = self.slack_purpose['value']
+ topic = self.slack_purpose["value"]
return unhtmlescape(unfurl_refs(topic))
def set_topic(self, value=None):
@@ -1923,7 +2234,9 @@ class SlackChannel(SlackChannelCommon):
if update_remote:
join_method = self.team.slack_api_translator[self.type].get("join")
if join_method:
- s = SlackRequest(self.team, join_method, {"channel": self.identifier}, channel=self)
+ s = SlackRequest(
+ self.team, join_method, {"channel": self.identifier}, channel=self
+ )
self.eventrouter.receive(s)
self.create_buffer()
self.active = True
@@ -1947,9 +2260,12 @@ class SlackChannel(SlackChannelCommon):
self.team = team
def highlights(self):
- nick_highlights = {'@' + self.team.nick, self.team.myidentifier}
- subteam_highlights = {subteam.handle for subteam in self.team.subteams.values()
- if subteam.is_member}
+ nick_highlights = {"@" + self.team.nick, self.team.myidentifier}
+ subteam_highlights = {
+ subteam.handle
+ for subteam in self.team.subteams.values()
+ if subteam.is_member
+ }
highlights = nick_highlights | subteam_highlights | self.team.highlight_words
if self.muted and config.muted_channels_activity == "personal_highlights":
return highlights
@@ -1967,10 +2283,15 @@ class SlackChannel(SlackChannelCommon):
w.buffer_set(self.channel_buffer, "notify", notify_level)
else:
buffer_full_name = w.buffer_get_string(self.channel_buffer, "full_name")
- w.command(self.channel_buffer, "/mute /unset weechat.notify.{}".format(buffer_full_name))
+ w.command(
+ self.channel_buffer,
+ "/mute /unset weechat.notify.{}".format(buffer_full_name),
+ )
if self.muted and config.muted_channels_activity == "none":
- w.buffer_set(self.channel_buffer, "highlight_tags_restrict", "highlight_force")
+ w.buffer_set(
+ self.channel_buffer, "highlight_tags_restrict", "highlight_force"
+ )
else:
w.buffer_set(self.channel_buffer, "highlight_tags_restrict", "")
@@ -1983,15 +2304,29 @@ class SlackChannel(SlackChannelCommon):
"""
if not self.channel_buffer:
self.active = True
- self.channel_buffer = w.buffer_new(self.formatted_name(style="long_default"), "buffer_input_callback", "EVENTROUTER", "", "")
- self.eventrouter.weechat_controller.register_buffer(self.channel_buffer, self)
+ self.channel_buffer = w.buffer_new(
+ self.formatted_name(style="long_default"),
+ "buffer_input_callback",
+ "EVENTROUTER",
+ "",
+ "",
+ )
+ self.eventrouter.weechat_controller.register_buffer(
+ self.channel_buffer, self
+ )
w.buffer_set(self.channel_buffer, "input_multiline", "1")
- w.buffer_set(self.channel_buffer, "localvar_set_type", get_localvar_type(self.type))
+ w.buffer_set(
+ self.channel_buffer, "localvar_set_type", get_localvar_type(self.type)
+ )
w.buffer_set(self.channel_buffer, "localvar_set_slack_type", self.type)
- w.buffer_set(self.channel_buffer, "localvar_set_channel", self.formatted_name())
+ w.buffer_set(
+ self.channel_buffer, "localvar_set_channel", self.formatted_name()
+ )
w.buffer_set(self.channel_buffer, "localvar_set_nick", self.team.nick)
self.buffer_rename_in_progress = True
- w.buffer_set(self.channel_buffer, "short_name", self.formatted_name(style="sidebar"))
+ w.buffer_set(
+ self.channel_buffer, "short_name", self.formatted_name(style="sidebar")
+ )
self.buffer_rename_in_progress = False
self.set_highlights()
self.set_topic()
@@ -2001,24 +2336,45 @@ class SlackChannel(SlackChannelCommon):
info_method = self.team.slack_api_translator[self.type].get("info")
if info_method:
- s = SlackRequest(self.team, info_method, {"channel": self.identifier}, channel=self)
+ s = SlackRequest(
+ self.team, info_method, {"channel": self.identifier}, channel=self
+ )
self.eventrouter.receive(s)
if self.type == "im":
join_method = self.team.slack_api_translator[self.type].get("join")
if join_method:
- s = SlackRequest(self.team, join_method, {"users": self.user, "return_im": True}, channel=self)
+ s = SlackRequest(
+ self.team,
+ join_method,
+ {"users": self.user, "return_im": True},
+ channel=self,
+ )
self.eventrouter.receive(s)
def destroy_buffer(self, update_remote):
super(SlackChannel, self).destroy_buffer(update_remote)
self.messages = OrderedDict()
if update_remote and not self.eventrouter.shutting_down:
- s = SlackRequest(self.team, self.team.slack_api_translator[self.type]["leave"],
- {"channel": self.identifier}, channel=self)
+ s = SlackRequest(
+ self.team,
+ self.team.slack_api_translator[self.type]["leave"],
+ {"channel": self.identifier},
+ channel=self,
+ )
self.eventrouter.receive(s)
- def buffer_prnt(self, nick, text, timestamp, tagset, tag_nick=None, history_message=False, no_log=False, extra_tags=None):
+ def buffer_prnt(
+ self,
+ nick,
+ text,
+ timestamp,
+ tagset,
+ tag_nick=None,
+ history_message=False,
+ no_log=False,
+ extra_tags=None,
+ ):
data = "{}\t{}".format(format_nick(nick, self.last_line_from), text)
self.last_line_from = nick
ts = SlackTS(timestamp)
@@ -2033,10 +2389,21 @@ class SlackChannel(SlackChannelCommon):
no_log = no_log or history_message and backlog
self_msg = tag_nick == self.team.nick
- tags = tag(ts, tagset, user=tag_nick, self_msg=self_msg, backlog=backlog, no_log=no_log, extra_tags=extra_tags)
+ tags = tag(
+ ts,
+ tagset,
+ user=tag_nick,
+ self_msg=self_msg,
+ backlog=backlog,
+ no_log=no_log,
+ extra_tags=extra_tags,
+ )
- if (config.unhide_buffers_with_activity
- and not self.is_visible() and not self.muted):
+ if (
+ config.unhide_buffers_with_activity
+ and not self.is_visible()
+ and not self.muted
+ ):
w.buffer_set(self.channel_buffer, "hidden", "0")
if no_log:
@@ -2058,9 +2425,12 @@ class SlackChannel(SlackChannelCommon):
self.messages[message_to_store.ts] = message_to_store
self.messages = OrderedDict(sorted(self.messages.items()))
- max_history = w.config_integer(w.config_get("weechat.history.max_buffer_lines_number"))
- messages_to_check = islice(self.messages.items(),
- max(0, len(self.messages) - max_history))
+ max_history = w.config_integer(
+ w.config_get("weechat.history.max_buffer_lines_number")
+ )
+ messages_to_check = islice(
+ self.messages.items(), max(0, len(self.messages) - max_history)
+ )
messages_to_delete = []
for (ts, message) in messages_to_check:
if ts == message_to_store.ts:
@@ -2070,8 +2440,11 @@ class SlackChannel(SlackChannelCommon):
if thread_channel is None or not thread_channel.active:
messages_to_delete.append(ts)
elif message.number_of_replies():
- if ((message.thread_channel is None or not message.thread_channel.active) and
- not any(submessage in self.messages for submessage in message.submessages)):
+ if (
+ message.thread_channel is None or not message.thread_channel.active
+ ) and not any(
+ submessage in self.messages for submessage in message.submessages
+ ):
messages_to_delete.append(ts)
else:
messages_to_delete.append(ts)
@@ -2097,8 +2470,13 @@ class SlackChannel(SlackChannelCommon):
if self.got_history and self.messages and not full:
post_data["oldest"] = next(reversed(self.messages))
- s = SlackRequest(self.team, self.team.slack_api_translator[self.type]["history"],
- post_data, channel=self, metadata={"slow_queue": slow_queue, "no_log": no_log})
+ s = SlackRequest(
+ self.team,
+ self.team.slack_api_translator[self.type]["history"],
+ post_data,
+ channel=self,
+ metadata={"slow_queue": slow_queue, "no_log": no_log},
+ )
self.eventrouter.receive(s, slow_queue)
self.got_history = True
self.history_needs_update = False
@@ -2114,11 +2492,18 @@ class SlackChannel(SlackChannelCommon):
thread_channel.print_getting_history()
self.pending_history_requests.add(thread_ts)
- post_data = {"channel": self.identifier, "ts": thread_ts,
- "limit": config.history_fetch_count}
- s = SlackRequest(self.team, "conversations.replies",
- post_data, channel=self,
- metadata={"thread_ts": thread_ts, "no_log": no_log})
+ post_data = {
+ "channel": self.identifier,
+ "ts": thread_ts,
+ "limit": config.history_fetch_count,
+ }
+ s = SlackRequest(
+ self.team,
+ "conversations.replies",
+ post_data,
+ channel=self,
+ metadata={"thread_ts": thread_ts, "no_log": no_log},
+ )
self.eventrouter.receive(s, slow_queue)
# Typing related
@@ -2172,18 +2557,38 @@ class SlackChannel(SlackChannelCommon):
w.buffer_set(self.channel_buffer, "nicklist", "1")
# create nicklists for the current channel if they don't exist
# if they do, use the existing pointer
- here = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_HERE)
+ here = w.nicklist_search_group(self.channel_buffer, "", NICK_GROUP_HERE)
if not here:
- here = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_HERE, "weechat.color.nicklist_group", 1)
- afk = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_AWAY)
+ here = w.nicklist_add_group(
+ self.channel_buffer,
+ "",
+ NICK_GROUP_HERE,
+ "weechat.color.nicklist_group",
+ 1,
+ )
+ afk = w.nicklist_search_group(self.channel_buffer, "", NICK_GROUP_AWAY)
if not afk:
- afk = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_AWAY, "weechat.color.nicklist_group", 1)
+ afk = w.nicklist_add_group(
+ self.channel_buffer,
+ "",
+ NICK_GROUP_AWAY,
+ "weechat.color.nicklist_group",
+ 1,
+ )
# Add External nicklist group only for shared channels
- if self.type == 'shared':
- external = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_EXTERNAL)
+ if self.type == "shared":
+ external = w.nicklist_search_group(
+ self.channel_buffer, "", NICK_GROUP_EXTERNAL
+ )
if not external:
- external = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_EXTERNAL, 'weechat.color.nicklist_group', 2)
+ external = w.nicklist_add_group(
+ self.channel_buffer,
+ "",
+ NICK_GROUP_EXTERNAL,
+ "weechat.color.nicklist_group",
+ 2,
+ )
if user and len(self.members) < 1000:
user = self.team.users.get(user)
@@ -2200,7 +2605,15 @@ class SlackChannel(SlackChannelCommon):
elif self.team.is_user_present(user.identifier):
nick_group = here
if user.identifier in self.members:
- w.nicklist_add_nick(self.channel_buffer, nick_group, user.name, user.color_name, "", "", 1)
+ w.nicklist_add_nick(
+ self.channel_buffer,
+ nick_group,
+ user.name,
+ user.color_name,
+ "",
+ "",
+ 1,
+ )
# if we didn't get a user, build a complete list. this is expensive.
else:
@@ -2215,21 +2628,36 @@ class SlackChannel(SlackChannelCommon):
nick_group = external
elif self.team.is_user_present(user.identifier):
nick_group = here
- w.nicklist_add_nick(self.channel_buffer, nick_group, user.name, user.color_name, "", "", 1)
+ w.nicklist_add_nick(
+ self.channel_buffer,
+ nick_group,
+ user.name,
+ user.color_name,
+ "",
+ "",
+ 1,
+ )
except:
- dbg("DEBUG: {} {} {}".format(self.identifier, self.name, format_exc_only()))
+ dbg(
+ "DEBUG: {} {} {}".format(
+ self.identifier, self.name, format_exc_only()
+ )
+ )
else:
w.nicklist_remove_all(self.channel_buffer)
for fn in ["1| too", "2| many", "3| users", "4| to", "5| show"]:
- w.nicklist_add_group(self.channel_buffer, '', fn, w.color('white'), 1)
+ w.nicklist_add_group(
+ self.channel_buffer, "", fn, w.color("white"), 1
+ )
def render(self, message, force=False):
text = message.render(force)
if isinstance(message, SlackThreadMessage):
thread_hash = self.hashed_messages[message.thread_ts]
hash_str = colorize_string(
- get_thread_color(str(thread_hash)), '[{}]'.format(thread_hash))
- return '{} {}'.format(hash_str, text)
+ get_thread_color(str(thread_hash)), "[{}]".format(thread_hash)
+ )
+ return "{} {}".format(hash_str, text)
return text
@@ -2254,8 +2682,11 @@ class SlackChannelVisibleMessages(MappingReversible):
return False
message = self.get(ts)
- if (type(message) == SlackThreadMessage and message.subtype != "thread_broadcast" and
- not config.thread_messages_in_channel):
+ if (
+ type(message) == SlackThreadMessage
+ and message.subtype != "thread_broadcast"
+ and not config.thread_messages_in_channel
+ ):
return False
return True
@@ -2335,13 +2766,13 @@ class SlackDMChannel(SlackChannel):
def set_related_server(self, team):
super(SlackDMChannel, self).set_related_server(team)
if self.user not in self.team.users:
- s = SlackRequest(self.team, 'users.info', {'user': self.user}, channel=self)
+ s = SlackRequest(self.team, "users.info", {"user": self.user}, channel=self)
self.eventrouter.receive(s)
def create_buffer(self):
if not self.channel_buffer:
super(SlackDMChannel, self).create_buffer()
- w.buffer_set(self.channel_buffer, "localvar_set_type", 'private')
+ w.buffer_set(self.channel_buffer, "localvar_set_type", "private")
def update_color(self):
if config.colorize_private_chats:
@@ -2354,12 +2785,19 @@ class SlackDMChannel(SlackChannel):
self.get_history()
info_method = self.team.slack_api_translator[self.type].get("info")
if info_method:
- s = SlackRequest(self.team, info_method, {"name": self.identifier}, channel=self)
+ s = SlackRequest(
+ self.team, info_method, {"name": self.identifier}, channel=self
+ )
self.eventrouter.receive(s)
if update_remote:
join_method = self.team.slack_api_translator[self.type].get("join")
if join_method:
- s = SlackRequest(self.team, join_method, {"users": self.user, "return_im": True}, channel=self)
+ s = SlackRequest(
+ self.team,
+ join_method,
+ {"users": self.user, "return_im": True},
+ channel=self,
+ )
self.eventrouter.receive(s)
@@ -2385,7 +2823,12 @@ class SlackPrivateChannel(SlackGroupChannel):
def get_history(self, slow_queue=False, full=False, no_log=False):
# Fetch members since they aren't included in rtm.start
- s = SlackRequest(self.team, 'conversations.members', {'channel': self.identifier}, channel=self)
+ s = SlackRequest(
+ self.team,
+ "conversations.members",
+ {"channel": self.identifier},
+ channel=self,
+ )
self.eventrouter.receive(s)
super(SlackPrivateChannel, self).get_history(slow_queue, full, no_log)
@@ -2397,11 +2840,13 @@ class SlackMPDMChannel(SlackChannel):
"""
def __init__(self, eventrouter, team_users, myidentifier, **kwargs):
- kwargs["name"] = ','.join(sorted(
- getattr(team_users.get(user_id), 'name', user_id)
+ kwargs["name"] = ",".join(
+ sorted(
+ getattr(team_users.get(user_id), "name", user_id)
for user_id in kwargs["members"]
if user_id != myidentifier
- ))
+ )
+ )
super(SlackMPDMChannel, self).__init__(eventrouter, "mpim", **kwargs)
def open(self, update_remote=True):
@@ -2410,12 +2855,19 @@ class SlackMPDMChannel(SlackChannel):
self.get_history()
info_method = self.team.slack_api_translator[self.type].get("info")
if info_method:
- s = SlackRequest(self.team, info_method, {"channel": self.identifier}, channel=self)
+ s = SlackRequest(
+ self.team, info_method, {"channel": self.identifier}, channel=self
+ )
self.eventrouter.receive(s)
if update_remote:
join_method = self.team.slack_api_translator[self.type].get("join")
if join_method:
- s = SlackRequest(self.team, join_method, {'users': ','.join(self.members)}, channel=self)
+ s = SlackRequest(
+ self.team,
+ join_method,
+ {"users": ",".join(self.members)},
+ channel=self,
+ )
self.eventrouter.receive(s)
@@ -2425,7 +2877,12 @@ class SlackSharedChannel(SlackChannel):
def get_history(self, slow_queue=False, full=False, no_log=False):
# Fetch members since they aren't included in rtm.start
- s = SlackRequest(self.team, 'conversations.members', {'channel': self.identifier, 'limit': 1000}, channel=self)
+ s = SlackRequest(
+ self.team,
+ "conversations.members",
+ {"channel": self.identifier, "limit": 1000},
+ channel=self,
+ )
self.eventrouter.receive(s)
super(SlackSharedChannel, self).get_history(slow_queue, full, no_log)
@@ -2520,9 +2977,21 @@ class SlackThreadChannel(SlackChannelCommon):
return
args = {"thread_ts": self.thread_ts}
args.update(post_data)
- super(SlackThreadChannel, self).mark_read(ts=ts, update_remote=update_remote, force=force, post_data=args)
+ super(SlackThreadChannel, self).mark_read(
+ ts=ts, update_remote=update_remote, force=force, post_data=args
+ )
- def buffer_prnt(self, nick, text, timestamp, tagset, tag_nick=None, history_message=False, no_log=False, extra_tags=None):
+ def buffer_prnt(
+ self,
+ nick,
+ text,
+ timestamp,
+ tagset,
+ tag_nick=None,
+ history_message=False,
+ no_log=False,
+ extra_tags=None,
+ ):
data = "{}\t{}".format(format_nick(nick, self.last_line_from), text)
self.last_line_from = nick
ts = SlackTS(timestamp)
@@ -2534,7 +3003,15 @@ class SlackThreadChannel(SlackChannelCommon):
no_log = no_log or history_message and backlog
self_msg = tag_nick == self.team.nick
- tags = tag(ts, tagset, user=tag_nick, self_msg=self_msg, backlog=backlog, no_log=no_log, extra_tags=extra_tags)
+ tags = tag(
+ ts,
+ tagset,
+ user=tag_nick,
+ self_msg=self_msg,
+ backlog=backlog,
+ no_log=no_log,
+ extra_tags=extra_tags,
+ )
if no_log:
w.buffer_set(self.channel_buffer, "print_hooks_enabled", "0")
@@ -2552,12 +3029,16 @@ class SlackThreadChannel(SlackChannelCommon):
if not any_msg_is_none:
self.reprint_messages(history_message=True, no_log=no_log)
- if (full or any_msg_is_none or
- len(self.parent_message.submessages) < self.parent_message.number_of_replies()):
+ if (
+ full
+ or any_msg_is_none
+ or len(self.parent_message.submessages)
+ < self.parent_message.number_of_replies()
+ ):
self.parent_channel.get_thread_history(self.thread_ts, slow_queue, no_log)
def send_message(self, message, subtype=None, request_dict_ext={}):
- if subtype == 'me_message':
+ if subtype == "me_message":
w.prnt("", "ERROR: /me is not supported in threads")
return w.WEECHAT_RC_ERROR
@@ -2578,8 +3059,12 @@ class SlackThreadChannel(SlackChannelCommon):
def rename(self):
if self.channel_buffer:
self.buffer_rename_in_progress = True
- w.buffer_set(self.channel_buffer, "name", self.formatted_name(style="long_default"))
- w.buffer_set(self.channel_buffer, "short_name", self.formatted_name(style="sidebar"))
+ w.buffer_set(
+ self.channel_buffer, "name", self.formatted_name(style="long_default")
+ )
+ w.buffer_set(
+ self.channel_buffer, "short_name", self.formatted_name(style="sidebar")
+ )
self.buffer_rename_in_progress = False
def set_highlights(self, highlight_string=None):
@@ -2593,22 +3078,43 @@ class SlackThreadChannel(SlackChannelCommon):
Creates the weechat buffer where the thread magic happens.
"""
if not self.channel_buffer:
- self.channel_buffer = w.buffer_new(self.formatted_name(style="long_default"), "buffer_input_callback", "EVENTROUTER", "", "")
- self.eventrouter.weechat_controller.register_buffer(self.channel_buffer, self)
+ self.channel_buffer = w.buffer_new(
+ self.formatted_name(style="long_default"),
+ "buffer_input_callback",
+ "EVENTROUTER",
+ "",
+ "",
+ )
+ self.eventrouter.weechat_controller.register_buffer(
+ self.channel_buffer, self
+ )
w.buffer_set(self.channel_buffer, "input_multiline", "1")
- w.buffer_set(self.channel_buffer, "localvar_set_type", get_localvar_type(self.parent_channel.type))
+ w.buffer_set(
+ self.channel_buffer,
+ "localvar_set_type",
+ get_localvar_type(self.parent_channel.type),
+ )
w.buffer_set(self.channel_buffer, "localvar_set_slack_type", self.type)
w.buffer_set(self.channel_buffer, "localvar_set_nick", self.team.nick)
- w.buffer_set(self.channel_buffer, "localvar_set_channel", self.formatted_name())
+ w.buffer_set(
+ self.channel_buffer, "localvar_set_channel", self.formatted_name()
+ )
w.buffer_set(self.channel_buffer, "localvar_set_server", self.team.name)
self.buffer_rename_in_progress = True
- w.buffer_set(self.channel_buffer, "short_name", self.formatted_name(style="sidebar"))
+ w.buffer_set(
+ self.channel_buffer, "short_name", self.formatted_name(style="sidebar")
+ )
self.buffer_rename_in_progress = False
self.set_highlights()
- time_format = w.config_string(w.config_get("weechat.look.buffer_time_format"))
+ time_format = w.config_string(
+ w.config_get("weechat.look.buffer_time_format")
+ )
parent_time = time.localtime(SlackTS(self.thread_ts).major)
- topic = '{} {} | {}'.format(time.strftime(time_format, parent_time),
- self.parent_message.sender, self.render(self.parent_message))
+ topic = "{} {} | {}".format(
+ time.strftime(time_format, parent_time),
+ self.parent_message.sender,
+ self.render(self.parent_message),
+ )
w.buffer_set(self.channel_buffer, "title", topic)
def destroy_buffer(self, update_remote):
@@ -2634,7 +3140,10 @@ class SlackThreadChannelMessages(MappingReversible):
return self.thread_channel.parent_message
def __getitem__(self, key):
- if key != self._parent_message.ts and key not in self._parent_message.submessages:
+ if (
+ key != self._parent_message.ts
+ and key not in self._parent_message.submessages
+ ):
raise KeyError(key)
return self.thread_channel.parent_channel.messages[key]
@@ -2664,8 +3173,9 @@ class SlackUser(object):
self.profile = {}
self.presence = kwargs.get("presence", "unknown")
self.deleted = kwargs.get("deleted", False)
- self.is_external = (not kwargs.get("is_bot") and
- kwargs.get("team_id") != originating_team_id)
+ self.is_external = (
+ not kwargs.get("is_bot") and kwargs.get("team_id") != originating_team_id
+ )
for key, value in kwargs.items():
setattr(self, key, value)
@@ -2701,6 +3211,7 @@ class SlackBot(SlackUser):
Basically the same as a user, but split out to identify and for future
needs
"""
+
def __init__(self, originating_team_id, **kwargs):
super(SlackBot, self).__init__(originating_team_id, is_bot=True, **kwargs)
@@ -2713,14 +3224,15 @@ class SlackMessage(object):
Note: these can't be tied to a SlackUser object because users
can be deleted, so we have to store sender in each one.
"""
+
def __init__(self, subtype, message_json, channel):
self.team = channel.team
self.channel = channel
self.subtype = subtype
- self.user_identifier = message_json.get('user')
+ self.user_identifier = message_json.get("user")
self.message_json = message_json
self.submessages = []
- self.ts = SlackTS(message_json['ts'])
+ self.ts = SlackTS(message_json["ts"])
self.subscribed = message_json.get("subscribed", False)
self.last_read = SlackTS(message_json.get("last_read", 0))
self.last_notify = SlackTS(0)
@@ -2738,7 +3250,9 @@ class SlackMessage(object):
def open_thread(self, switch=False):
if not self.thread_channel or not self.thread_channel.active:
- self.channel.thread_channels[self.ts] = SlackThreadChannel(EVENTROUTER, self.channel, self.ts)
+ self.channel.thread_channels[self.ts] = SlackThreadChannel(
+ EVENTROUTER, self.channel, self.ts
+ )
self.thread_channel.open()
if switch:
w.buffer_set(self.thread_channel.channel_buffer, "display", "1")
@@ -2762,33 +3276,47 @@ class SlackMessage(object):
else:
text = self.message_json.get("text", "")
- if self.message_json.get('mrkdwn', True):
+ if self.message_json.get("mrkdwn", True):
text = render_formatting(text)
- if (self.message_json.get('subtype') in ('channel_join', 'group_join') and
- self.message_json.get('inviter')):
- inviter_id = self.message_json.get('inviter')
+ if (
+ self.message_json.get("subtype")
+ in (
+ "channel_join",
+ "group_join",
+ )
+ and self.message_json.get("inviter")
+ ):
+ inviter_id = self.message_json.get("inviter")
text += " by invitation from <@{}>".format(inviter_id)
text = unfurl_refs(text)
- if (self.subtype == 'me_message' and
- not self.message_json['text'].startswith(self.sender)):
+ if self.subtype == "me_message" and not self.message_json["text"].startswith(
+ self.sender
+ ):
text = "{} {}".format(self.sender, text)
if "edited" in self.message_json:
- text += " " + colorize_string(config.color_edited_suffix, '(edited)')
+ text += " " + colorize_string(config.color_edited_suffix, "(edited)")
text += unfurl_refs(unwrap_attachments(self.message_json, text))
text += unfurl_refs(unwrap_files(self.message_json, text))
text = unhtmlescape(text.lstrip().replace("\t", " "))
text += create_reactions_string(
- self.message_json.get("reactions", ""), self.team.myidentifier)
+ self.message_json.get("reactions", ""), self.team.myidentifier
+ )
if self.number_of_replies():
- text += " " + colorize_string(get_thread_color(self.hash), "[ Thread: {} Replies: {}{} ]".format(
- self.hash, self.number_of_replies(), " Subscribed" if self.subscribed else ""))
+ text += " " + colorize_string(
+ get_thread_color(self.hash),
+ "[ Thread: {} Replies: {}{} ]".format(
+ self.hash,
+ self.number_of_replies(),
+ " Subscribed" if self.subscribed else "",
+ ),
+ )
text = replace_string_with_emoji(text)
@@ -2806,14 +3334,16 @@ class SlackMessage(object):
if user.is_external:
name += config.external_user_suffix
return name
- elif 'user_profile' in self.message_json:
- nick = nick_from_profile(self.message_json['user_profile'], self.user_identifier)
+ elif "user_profile" in self.message_json:
+ nick = nick_from_profile(
+ self.message_json["user_profile"], self.user_identifier
+ )
color_name = get_nick_color(nick)
name = nick if plain else colorize_string(color_name, nick)
- if self.message_json.get('user_team') != self.message_json.get('team'):
+ if self.message_json.get("user_team") != self.message_json.get("team"):
name += config.external_user_suffix
return name
- elif 'username' in self.message_json:
+ elif "username" in self.message_json:
username = self.message_json["username"]
if plain:
return username
@@ -2821,13 +3351,13 @@ class SlackMessage(object):
return "{} :]".format(username)
else:
return "-{}-".format(username)
- elif 'service_name' in self.message_json:
+ elif "service_name" in self.message_json:
service_name = self.message_json["service_name"]
if plain:
return service_name
else:
return "-{}-".format(service_name)
- elif self.message_json.get('bot_id') in self.team.bots:
+ elif self.message_json.get("bot_id") in self.team.bots:
bot = self.team.bots[self.message_json["bot_id"]]
name = bot.formatted_name(enable_color=not plain)
if plain:
@@ -2858,7 +3388,9 @@ class SlackMessage(object):
else:
if "reactions" not in self.message_json:
self.message_json["reactions"] = []
- self.message_json["reactions"].append({"name": reaction_name, "users": [user]})
+ self.message_json["reactions"].append(
+ {"name": reaction_name, "users": [user]}
+ )
def remove_reaction(self, reaction_name, user):
reaction = self.get_reaction(reaction_name)
@@ -2866,8 +3398,10 @@ class SlackMessage(object):
reaction["users"].remove(user)
def has_mention(self):
- return w.string_has_highlight(unfurl_refs(self.message_json.get('text')),
- ",".join(self.channel.highlights()))
+ return w.string_has_highlight(
+ unfurl_refs(self.message_json.get("text")),
+ ",".join(self.channel.highlights()),
+ )
def number_of_replies(self):
return max(len(self.submessages), self.message_json.get("reply_count", 0))
@@ -2878,8 +3412,12 @@ class SlackMessage(object):
return
message = self.channel.messages.get(self.submessages[-1])
- if (self.thread_channel and self.thread_channel.active or
- message.ts <= self.last_read or message.ts <= self.last_notify):
+ if (
+ self.thread_channel
+ and self.thread_channel.active
+ or message.ts <= self.last_read
+ or message.ts <= self.last_notify
+ ):
return
if message.has_mention():
@@ -2894,17 +3432,26 @@ class SlackMessage(object):
if config.auto_open_threads:
self.open_thread()
- if message.user_identifier != self.team.myidentifier and (config.notify_subscribed_threads == True or
- config.notify_subscribed_threads == "auto" and not config.auto_open_threads and
- not config.thread_messages_in_channel):
- message = template.format(hash=self.hash, channel=self.channel.formatted_name())
+ if message.user_identifier != self.team.myidentifier and (
+ config.notify_subscribed_threads == True
+ or config.notify_subscribed_threads == "auto"
+ and not config.auto_open_threads
+ and not config.thread_messages_in_channel
+ ):
+ message = template.format(
+ hash=self.hash, channel=self.channel.formatted_name()
+ )
self.team.buffer_prnt(message, message=True)
-class SlackThreadMessage(SlackMessage):
+class SlackThreadMessage(SlackMessage):
def __init__(self, parent_channel, thread_ts, message_json, *args):
- subtype = message_json.get('subtype',
- 'thread_broadcast' if message_json.get("reply_broadcast") else 'thread_message')
+ subtype = message_json.get(
+ "subtype",
+ "thread_broadcast"
+ if message_json.get("reply_broadcast")
+ else "thread_message",
+ )
super(SlackThreadMessage, self).__init__(subtype, message_json, *args)
self.parent_channel = parent_channel
self.thread_ts = thread_ts
@@ -2916,20 +3463,19 @@ class SlackThreadMessage(SlackMessage):
class Hdata(object):
def __init__(self, w):
- self.buffer = w.hdata_get('buffer')
- self.line = w.hdata_get('line')
- self.line_data = w.hdata_get('line_data')
- self.lines = w.hdata_get('lines')
+ self.buffer = w.hdata_get("buffer")
+ self.line = w.hdata_get("line")
+ self.line_data = w.hdata_get("line_data")
+ self.lines = w.hdata_get("lines")
class SlackTS(object):
-
def __init__(self, ts=None):
if isinstance(ts, int):
self.major = ts
self.minor = 0
elif ts is not None:
- self.major, self.minor = [int(x) for x in ts.split('.', 1)]
+ self.major, self.minor = [int(x) for x in ts.split(".", 1)]
else:
self.major = int(time.time())
self.minor = 0
@@ -2989,6 +3535,7 @@ class SlackTS(object):
def minorstr(self):
return str(self.minor)
+
###### New handlers
@@ -2999,11 +3546,18 @@ def handle_rtmstart(login_data, eventrouter, team, channel, metadata):
metadata = login_data["wee_slack_request_metadata"]
if not login_data["ok"]:
- w.prnt("", "ERROR: Failed connecting to Slack with token {}: {}"
- .format(token_for_print(metadata.token), login_data["error"]))
+ w.prnt(
+ "",
+ "ERROR: Failed connecting to Slack with token {}: {}".format(
+ token_for_print(metadata.token), login_data["error"]
+ ),
+ )
if not re.match(r"^xo\w\w(-\d+){3}-[0-9a-f]+$", metadata.token):
- w.prnt("", "ERROR: Token does not look like a valid Slack token. "
- "Ensure it is a valid token and not just a OAuth code.")
+ w.prnt(
+ "",
+ "ERROR: Token does not look like a valid Slack token. "
+ "Ensure it is a valid token and not just a OAuth code.",
+ )
return
@@ -3015,22 +3569,25 @@ def handle_rtmstart(login_data, eventrouter, team, channel, metadata):
self_nick = nick_from_profile(self_profile, login_data["self"]["name"])
# Let's reuse a team if we have it already.
- th = SlackTeam.generate_team_hash(login_data['team']['id'], login_data['team']['domain'])
+ th = SlackTeam.generate_team_hash(
+ login_data["team"]["id"], login_data["team"]["domain"]
+ )
if not eventrouter.teams.get(th):
users = {}
for item in login_data["users"]:
- users[item["id"]] = SlackUser(login_data['team']['id'], **item)
+ users[item["id"]] = SlackUser(login_data["team"]["id"], **item)
bots = {}
for item in login_data["bots"]:
- bots[item["id"]] = SlackBot(login_data['team']['id'], **item)
+ bots[item["id"]] = SlackBot(login_data["team"]["id"], **item)
subteams = {}
for item in login_data["subteams"]["all"]:
- is_member = item['id'] in login_data["subteams"]["self"]
- subteams[item['id']] = SlackSubteam(
- login_data['team']['id'], is_member=is_member, **item)
+ is_member = item["id"] in login_data["subteams"]["self"]
+ subteams[item["id"]] = SlackSubteam(
+ login_data["team"]["id"], is_member=is_member, **item
+ )
channels = {}
for item in login_data["channels"]:
@@ -3046,7 +3603,9 @@ def handle_rtmstart(login_data, eventrouter, team, channel, metadata):
for item in login_data["groups"]:
if item["is_mpim"]:
- channels[item["id"]] = SlackMPDMChannel(eventrouter, users, login_data["self"]["id"], **item)
+ channels[item["id"]] = SlackMPDMChannel(
+ eventrouter, users, login_data["self"]["id"], **item
+ )
else:
channels[item["id"]] = SlackGroupChannel(eventrouter, **item)
@@ -3054,7 +3613,7 @@ def handle_rtmstart(login_data, eventrouter, team, channel, metadata):
eventrouter,
metadata.token,
th,
- login_data['url'],
+ login_data["url"],
login_data["team"],
subteams,
self_nick,
@@ -3072,25 +3631,35 @@ def handle_rtmstart(login_data, eventrouter, team, channel, metadata):
t = eventrouter.teams.get(th)
if t.myidentifier != login_data["self"]["id"]:
print_error(
- 'The Slack team {} has tokens for two different users, this is not supported. The '
- 'token {} is for user {}, and the token {} is for user {}. Please remove one of '
- 'them.'.format(t.team_info["name"], token_for_print(t.token), t.nick,
- token_for_print(metadata.token), self_nick)
+ "The Slack team {} has tokens for two different users, this is not supported. The "
+ "token {} is for user {}, and the token {} is for user {}. Please remove one of "
+ "them.".format(
+ t.team_info["name"],
+ token_for_print(t.token),
+ t.nick,
+ token_for_print(metadata.token),
+ self_nick,
+ )
)
return
- elif not metadata.metadata.get('reconnect'):
+ elif not metadata.metadata.get("reconnect"):
print_error(
- 'Ignoring duplicate Slack tokens for the same team ({}) and user ({}). The two '
- 'tokens are {} and {}.'.format(t.team_info["name"], t.nick,
- token_for_print(t.token), token_for_print(metadata.token)),
- warning=True
+ "Ignoring duplicate Slack tokens for the same team ({}) and user ({}). The two "
+ "tokens are {} and {}.".format(
+ t.team_info["name"],
+ t.nick,
+ token_for_print(t.token),
+ token_for_print(metadata.token),
+ ),
+ warning=True,
)
return
else:
- t.set_reconnect_url(login_data['url'])
+ t.set_reconnect_url(login_data["url"])
t.connecting_rtm = False
- t.connect(metadata.metadata['reconnect'])
+ t.connect(metadata.metadata["reconnect"])
+
def handle_rtmconnect(login_data, eventrouter, team, channel, metadata):
metadata = login_data["wee_slack_request_metadata"]
@@ -3098,12 +3667,16 @@ def handle_rtmconnect(login_data, eventrouter, team, channel, metadata):
team.connecting_rtm = False
if not login_data["ok"]:
- w.prnt("", "ERROR: Failed reconnecting to Slack with token {}: {}"
- .format(token_for_print(metadata.token), login_data["error"]))
+ w.prnt(
+ "",
+ "ERROR: Failed reconnecting to Slack with token {}: {}".format(
+ token_for_print(metadata.token), login_data["error"]
+ ),
+ )
return
- team.set_reconnect_url(login_data['url'])
- team.connect(metadata.metadata['reconnect'])
+ team.set_reconnect_url(login_data["url"])
+ team.connect(metadata.metadata["reconnect"])
def handle_emojilist(emoji_json, eventrouter, team, channel, metadata):
@@ -3112,39 +3685,68 @@ def handle_emojilist(emoji_json, eventrouter, team, channel, metadata):
def handle_channelsinfo(channel_json, eventrouter, team, channel, metadata):
- channel.set_unread_count_display(channel_json['channel'].get('unread_count_display', 0))
- channel.set_members(channel_json['channel']['members'])
+ channel.set_unread_count_display(
+ channel_json["channel"].get("unread_count_display", 0)
+ )
+ channel.set_members(channel_json["channel"]["members"])
def handle_groupsinfo(group_json, eventrouter, team, channel, metadatas):
- channel.set_unread_count_display(group_json['group'].get('unread_count_display', 0))
- channel.set_members(group_json['group']['members'])
+ channel.set_unread_count_display(group_json["group"].get("unread_count_display", 0))
+ channel.set_members(group_json["group"]["members"])
-def handle_conversationsopen(conversation_json, eventrouter, team, channel, metadata, object_name='channel'):
+def handle_conversationsopen(
+ conversation_json, eventrouter, team, channel, metadata, object_name="channel"
+):
# Set unread count if the channel isn't new
if channel:
- unread_count_display = conversation_json[object_name].get('unread_count_display', 0)
+ unread_count_display = conversation_json[object_name].get(
+ "unread_count_display", 0
+ )
channel.set_unread_count_display(unread_count_display)
-def handle_mpimopen(mpim_json, eventrouter, team, channel, metadata, object_name='group'):
- handle_conversationsopen(mpim_json, eventrouter, team, channel, metadata, object_name)
+def handle_mpimopen(
+ mpim_json, eventrouter, team, channel, metadata, object_name="group"
+):
+ handle_conversationsopen(
+ mpim_json, eventrouter, team, channel, metadata, object_name
+ )
-def handle_history(message_json, eventrouter, team, channel, metadata, includes_threads=True):
+def handle_history(
+ message_json, eventrouter, team, channel, metadata, includes_threads=True
+):
channel.got_history = True
channel.history_needs_update = False
for message in reversed(message_json["messages"]):
- message = process_message(message, eventrouter, team, channel, metadata, history_message=True)
- if (not includes_threads and message and message.number_of_replies() and
- (config.thread_messages_in_channel or message.subscribed and
- SlackTS(message.message_json.get("latest_reply", 0)) > message.last_read)):
- channel.get_thread_history(message.ts, metadata["slow_queue"], metadata["no_log"])
+ message = process_message(
+ message, eventrouter, team, channel, metadata, history_message=True
+ )
+ if (
+ not includes_threads
+ and message
+ and message.number_of_replies()
+ and (
+ config.thread_messages_in_channel
+ or message.subscribed
+ and SlackTS(message.message_json.get("latest_reply", 0))
+ > message.last_read
+ )
+ ):
+ channel.get_thread_history(
+ message.ts, metadata["slow_queue"], metadata["no_log"]
+ )
channel.pending_history_requests.discard(channel.identifier)
- if channel.visible_messages.first_ts_to_display.major == 0 and message_json["messages"]:
- channel.visible_messages.first_ts_to_display = SlackTS(message_json["messages"][-1]["ts"])
+ if (
+ channel.visible_messages.first_ts_to_display.major == 0
+ and message_json["messages"]
+ ):
+ channel.visible_messages.first_ts_to_display = SlackTS(
+ message_json["messages"][-1]["ts"]
+ )
channel.reprint_messages(history_message=True, no_log=metadata["no_log"])
for thread_channel in channel.thread_channels.values():
thread_channel.reprint_messages(history_message=True, no_log=metadata["no_log"])
@@ -3156,15 +3758,19 @@ handle_imhistory = handle_history
handle_mpimhistory = handle_history
-def handle_conversationshistory(message_json, eventrouter, team, channel, metadata, includes_threads=True):
+def handle_conversationshistory(
+ message_json, eventrouter, team, channel, metadata, includes_threads=True
+):
handle_history(message_json, eventrouter, team, channel, metadata, False)
def handle_conversationsreplies(message_json, eventrouter, team, channel, metadata):
- for message in message_json['messages']:
- process_message(message, eventrouter, team, channel, metadata, history_message=True)
- channel.pending_history_requests.discard(metadata.get('thread_ts'))
- thread_channel = channel.thread_channels.get(metadata.get('thread_ts'))
+ for message in message_json["messages"]:
+ process_message(
+ message, eventrouter, team, channel, metadata, history_message=True
+ )
+ channel.pending_history_requests.discard(metadata.get("thread_ts"))
+ thread_channel = channel.thread_channels.get(metadata.get("thread_ts"))
if thread_channel and thread_channel.active:
thread_channel.got_history = True
thread_channel.history_needs_update = False
@@ -3174,111 +3780,135 @@ def handle_conversationsreplies(message_json, eventrouter, team, channel, metada
def handle_conversationsmembers(members_json, eventrouter, team, channel, metadata):
- if members_json['ok']:
- channel.set_members(members_json['members'])
- unknown_users = set(members_json['members']) - set(team.users.keys())
+ if members_json["ok"]:
+ channel.set_members(members_json["members"])
+ unknown_users = set(members_json["members"]) - set(team.users.keys())
for user in unknown_users:
- s = SlackRequest(team, 'users.info', {'user': user}, channel=channel)
+ s = SlackRequest(team, "users.info", {"user": user}, channel=channel)
eventrouter.receive(s)
else:
- w.prnt(team.channel_buffer, '{}Couldn\'t load members for channel {}. Error: {}'
- .format(w.prefix('error'), channel.name, members_json['error']))
+ w.prnt(
+ team.channel_buffer,
+ "{}Couldn't load members for channel {}. Error: {}".format(
+ w.prefix("error"), channel.name, members_json["error"]
+ ),
+ )
def handle_usersinfo(user_json, eventrouter, team, channel, metadata):
- user_info = user_json['user']
- if not metadata.get('user'):
+ user_info = user_json["user"]
+ if not metadata.get("user"):
user = SlackUser(team.identifier, **user_info)
- team.users[user_info['id']] = user
+ team.users[user_info["id"]] = user
- if channel.type == 'shared':
- channel.update_nicklist(user_info['id'])
- elif channel.type == 'im':
+ if channel.type == "shared":
+ channel.update_nicklist(user_info["id"])
+ elif channel.type == "im":
channel.set_name(user.name)
channel.set_topic(create_user_status_string(user.profile))
def handle_usergroupsuserslist(users_json, eventrouter, team, channel, metadata):
- header = 'Users in {}'.format(metadata['usergroup_handle'])
- users = [team.users[key] for key in users_json['users']]
+ header = "Users in {}".format(metadata["usergroup_handle"])
+ users = [team.users[key] for key in users_json["users"]]
return print_users_info(team, header, users)
def handle_usersprofileset(json, eventrouter, team, channel, metadata):
- if not json['ok']:
- w.prnt('', 'ERROR: Failed to set profile: {}'.format(json['error']))
+ if not json["ok"]:
+ w.prnt("", "ERROR: Failed to set profile: {}".format(json["error"]))
def handle_conversationscreate(json, eventrouter, team, channel, metadata):
metadata = json["wee_slack_request_metadata"]
- if not json['ok']:
+ if not json["ok"]:
name = metadata.post_data["name"]
- print_error("Couldn't create channel {}: {}".format(name, json['error']))
+ print_error("Couldn't create channel {}: {}".format(name, json["error"]))
def handle_conversationsinvite(json, eventrouter, team, channel, metadata):
- nicks = ', '.join(metadata['nicks'])
- if json['ok']:
- w.prnt(team.channel_buffer, 'Invited {} to {}'.format(nicks, channel.name))
+ nicks = ", ".join(metadata["nicks"])
+ if json["ok"]:
+ w.prnt(team.channel_buffer, "Invited {} to {}".format(nicks, channel.name))
else:
- w.prnt(team.channel_buffer, 'ERROR: Couldn\'t invite {} to {}. Error: {}'
- .format(nicks, channel.name, json['error']))
+ w.prnt(
+ team.channel_buffer,
+ "ERROR: Couldn't invite {} to {}. Error: {}".format(
+ nicks, channel.name, json["error"]
+ ),
+ )
def handle_chatcommand(json, eventrouter, team, channel, metadata):
- command = '{} {}'.format(metadata['command'], metadata['command_args']).rstrip()
- response = unfurl_refs(json['response']) if 'response' in json else ''
- if json['ok']:
- response_text = 'Response: {}'.format(response) if response else 'No response'
- w.prnt(team.channel_buffer, 'Ran command "{}". {}' .format(command, response_text))
+ command = "{} {}".format(metadata["command"], metadata["command_args"]).rstrip()
+ response = unfurl_refs(json["response"]) if "response" in json else ""
+ if json["ok"]:
+ response_text = "Response: {}".format(response) if response else "No response"
+ w.prnt(
+ team.channel_buffer, 'Ran command "{}". {}'.format(command, response_text)
+ )
else:
- response_text = '. Response: {}'.format(response) if response else ''
- w.prnt(team.channel_buffer, 'ERROR: Couldn\'t run command "{}". Error: {}{}'
- .format(command, json['error'], response_text))
+ response_text = ". Response: {}".format(response) if response else ""
+ w.prnt(
+ team.channel_buffer,
+ 'ERROR: Couldn\'t run command "{}". Error: {}{}'.format(
+ command, json["error"], response_text
+ ),
+ )
def handle_chatdelete(json, eventrouter, team, channel, metadata):
- if not json['ok']:
- print_error("Couldn't delete message: {}".format(json['error']))
+ if not json["ok"]:
+ print_error("Couldn't delete message: {}".format(json["error"]))
def handle_chatupdate(json, eventrouter, team, channel, metadata):
- if not json['ok']:
- print_error("Couldn't change message: {}".format(json['error']))
+ if not json["ok"]:
+ print_error("Couldn't change message: {}".format(json["error"]))
def handle_reactionsadd(json, eventrouter, team, channel, metadata):
- if not json['ok']:
- print_error("Couldn't add reaction {}: {}".format(metadata['reaction'], json['error']))
+ if not json["ok"]:
+ print_error(
+ "Couldn't add reaction {}: {}".format(metadata["reaction"], json["error"])
+ )
def handle_reactionsremove(json, eventrouter, team, channel, metadata):
- if not json['ok']:
- print_error("Couldn't remove reaction {}: {}".format(metadata['reaction'], json['error']))
+ if not json["ok"]:
+ print_error(
+ "Couldn't remove reaction {}: {}".format(
+ metadata["reaction"], json["error"]
+ )
+ )
def handle_subscriptionsthreadmark(json, eventrouter, team, channel, metadata):
if not json["ok"]:
- if json['error'] == 'not_allowed_token_type':
- team.slack_api_translator['thread']['mark'] = None
+ if json["error"] == "not_allowed_token_type":
+ team.slack_api_translator["thread"]["mark"] = None
else:
- print_error("Couldn't set thread read status: {}".format(json['error']))
+ print_error("Couldn't set thread read status: {}".format(json["error"]))
def handle_subscriptionsthreadadd(json, eventrouter, team, channel, metadata):
if not json["ok"]:
- if json['error'] == 'not_allowed_token_type':
- print_error("Can only subscribe to a thread when using a session token, see the readme: https://github.com/wee-slack/wee-slack#4-add-your-slack-api-tokens")
+ if json["error"] == "not_allowed_token_type":
+ print_error(
+ "Can only subscribe to a thread when using a session token, see the readme: https://github.com/wee-slack/wee-slack#4-add-your-slack-api-tokens"
+ )
else:
- print_error("Couldn't add thread subscription: {}".format(json['error']))
+ print_error("Couldn't add thread subscription: {}".format(json["error"]))
def handle_subscriptionsthreadremove(json, eventrouter, team, channel, metadata):
if not json["ok"]:
- if json['error'] == 'not_allowed_token_type':
- print_error("Can only unsubscribe from a thread when using a session token, see the readme: https://github.com/wee-slack/wee-slack#4-add-your-slack-api-tokens")
+ if json["error"] == "not_allowed_token_type":
+ print_error(
+ "Can only unsubscribe from a thread when using a session token, see the readme: https://github.com/wee-slack/wee-slack#4-add-your-slack-api-tokens"
+ )
else:
- print_error("Couldn't remove thread subscription: {}".format(json['error']))
+ print_error("Couldn't remove thread subscription: {}".format(json["error"]))
###### New/converted process_ and subprocess_ methods
@@ -3287,7 +3917,7 @@ def process_hello(message_json, eventrouter, team, channel, metadata):
def process_reconnect_url(message_json, eventrouter, team, channel, metadata):
- team.set_reconnect_url(message_json['url'])
+ team.set_reconnect_url(message_json["url"])
def process_presence_change(message_json, eventrouter, team, channel, metadata):
@@ -3308,23 +3938,23 @@ def process_manual_presence_change(message_json, eventrouter, team, channel, met
def process_pref_change(message_json, eventrouter, team, channel, metadata):
- if message_json['name'] == 'muted_channels':
- team.set_muted_channels(message_json['value'])
- elif message_json['name'] == 'highlight_words':
- team.set_highlight_words(message_json['value'])
+ if message_json["name"] == "muted_channels":
+ team.set_muted_channels(message_json["value"])
+ elif message_json["name"] == "highlight_words":
+ team.set_highlight_words(message_json["value"])
else:
- dbg("Preference change not implemented: {}\n".format(message_json['name']))
+ dbg("Preference change not implemented: {}\n".format(message_json["name"]))
def process_user_change(message_json, eventrouter, team, channel, metadata):
"""
Currently only used to update status, but lots here we could do.
"""
- user = metadata['user']
- profile = message_json['user']['profile']
+ user = metadata["user"]
+ profile = message_json["user"]["profile"]
if user:
- user.update_status(profile.get('status_emoji'), profile.get('status_text'))
- dmchannel = team.find_channel_by_members({user.identifier}, channel_type='im')
+ user.update_status(profile.get("status_emoji"), profile.get("status_text"))
+ dmchannel = team.find_channel_by_members({user.identifier}, channel_type="im")
if dmchannel:
dmchannel.set_topic(create_user_status_string(profile))
@@ -3336,7 +3966,7 @@ def process_user_typing(message_json, eventrouter, team, channel, metadata):
def process_team_join(message_json, eventrouter, team, channel, metadata):
- user = message_json['user']
+ user = message_json["user"]
team.users[user["id"]] = SlackUser(team.identifier, **user)
@@ -3344,17 +3974,27 @@ def process_pong(message_json, eventrouter, team, channel, metadata):
team.last_pong_time = time.time()
-def process_message(message_json, eventrouter, team, channel, metadata, history_message=False):
- if not history_message and "ts" in message_json and SlackTS(message_json["ts"]) in channel.messages:
+def process_message(
+ message_json, eventrouter, team, channel, metadata, history_message=False
+):
+ if (
+ not history_message
+ and "ts" in message_json
+ and SlackTS(message_json["ts"]) in channel.messages
+ ):
return
subtype = message_json.get("subtype")
subtype_functions = get_functions_with_prefix("subprocess_")
if "thread_ts" in message_json and "reply_count" not in message_json:
- message = subprocess_thread_message(message_json, eventrouter, team, channel, history_message)
+ message = subprocess_thread_message(
+ message_json, eventrouter, team, channel, history_message
+ )
elif subtype in subtype_functions:
- message = subtype_functions[subtype](message_json, eventrouter, team, channel, history_message)
+ message = subtype_functions[subtype](
+ message_json, eventrouter, team, channel, history_message
+ )
else:
message = SlackMessage(subtype or "normal", message_json, channel)
channel.store_message(message)
@@ -3379,8 +4019,12 @@ def download_files(message_json, team):
try:
os.makedirs(download_location)
except:
- w.prnt('', 'ERROR: Failed to create directory at files_download_location: {}'
- .format(format_exc_only()))
+ w.prnt(
+ "",
+ "ERROR: Failed to create directory at files_download_location: {}".format(
+ format_exc_only()
+ ),
+ )
def fileout_iter(path):
yield path
@@ -3388,27 +4032,32 @@ def download_files(message_json, team):
for i in count(start=1):
yield main + "-{}".format(i) + ext
- for f in message_json.get('files', []):
- if f.get('mode') == 'tombstone':
+ for f in message_json.get("files", []):
+ if f.get("mode") == "tombstone":
continue
- filetype = '' if f['title'].endswith(f['filetype']) else '.' + f['filetype']
- filename = '{}_{}{}'.format(team.name, f['title'], filetype)
+ filetype = "" if f["title"].endswith(f["filetype"]) else "." + f["filetype"]
+ filename = "{}_{}{}".format(team.name, f["title"], filetype)
for fileout in fileout_iter(os.path.join(download_location, filename)):
if os.path.isfile(fileout):
continue
w.hook_process_hashtable(
- "url:" + f['url_private'],
+ "url:" + f["url_private"],
{
- 'file_out': fileout,
- 'httpheader': 'Authorization: Bearer ' + team.token
+ "file_out": fileout,
+ "httpheader": "Authorization: Bearer " + team.token,
},
- config.slack_timeout, "", "")
+ config.slack_timeout,
+ "",
+ "",
+ )
break
-def subprocess_thread_message(message_json, eventrouter, team, channel, history_message):
- parent_ts = SlackTS(message_json['thread_ts'])
+def subprocess_thread_message(
+ message_json, eventrouter, team, channel, history_message
+):
+ parent_ts = SlackTS(message_json["thread_ts"])
message = SlackThreadMessage(channel, parent_ts, message_json, channel)
parent_message = message.parent_message
@@ -3442,7 +4091,7 @@ def subprocess_channel_join(message_json, eventrouter, team, channel, history_me
def subprocess_channel_leave(message_json, eventrouter, team, channel, history_message):
- message = SlackMessage("leave", message_json, channel)
+ message = SlackMessage("leave", message_json, channel)
channel.store_message(message)
channel.user_left(message_json["user"])
return message
@@ -3460,17 +4109,23 @@ subprocess_group_leave = subprocess_channel_leave
subprocess_group_topic = subprocess_channel_topic
-def subprocess_message_replied(message_json, eventrouter, team, channel, history_message):
+def subprocess_message_replied(
+ message_json, eventrouter, team, channel, history_message
+):
pass
-def subprocess_message_changed(message_json, eventrouter, team, channel, history_message):
+def subprocess_message_changed(
+ message_json, eventrouter, team, channel, history_message
+):
new_message = message_json.get("message")
channel.change_message(new_message["ts"], message_json=new_message)
-def subprocess_message_deleted(message_json, eventrouter, team, channel, history_message):
- message = colorize_string(config.color_deleted, '(deleted)')
+def subprocess_message_deleted(
+ message_json, eventrouter, team, channel, history_message
+):
+ message = colorize_string(config.color_deleted, "(deleted)")
channel.change_message(message_json["deleted_ts"], text=message)
@@ -3479,12 +4134,22 @@ def process_reply(message_json, eventrouter, team, channel, metadata):
original_message_json = team.ws_replies.pop(reply_to, None)
if original_message_json:
dbg("REPLY {}".format(message_json))
- channel = team.channels[original_message_json.get('channel')]
+ channel = team.channels[original_message_json.get("channel")]
if message_json["ok"]:
original_message_json.update(message_json)
- process_message(original_message_json, eventrouter, team=team, channel=channel, metadata={})
+ process_message(
+ original_message_json,
+ eventrouter,
+ team=team,
+ channel=channel,
+ metadata={},
+ )
else:
- print_error("Couldn't send message to channel {}: {}".format(channel.name, message_json["error"]))
+ print_error(
+ "Couldn't send message to channel {}: {}".format(
+ channel.name, message_json["error"]
+ )
+ )
else:
dbg("Unexpected reply {}".format(message_json))
@@ -3509,7 +4174,8 @@ def process_thread_marked(message_json, eventrouter, team, channel, metadata):
channel = team.channels.get(subscription.get("channel"))
if ts and thread_ts and channel:
thread_channel = channel.thread_channels.get(SlackTS(thread_ts))
- if thread_channel: thread_channel.mark_read(ts=ts, force=True, update_remote=False)
+ if thread_channel:
+ thread_channel.mark_read(ts=ts, force=True, update_remote=False)
else:
dbg("tried to mark something weird {}".format(message_json))
@@ -3521,21 +4187,21 @@ def process_channel_joined(message_json, eventrouter, team, channel, metadata):
def process_channel_created(message_json, eventrouter, team, channel, metadata):
item = message_json["channel"]
- item['is_member'] = False
+ item["is_member"] = False
channel = SlackChannel(eventrouter, team=team, **item)
team.channels[item["id"]] = channel
- team.buffer_prnt('Channel created: {}'.format(channel.name))
+ team.buffer_prnt("Channel created: {}".format(channel.name))
def process_channel_rename(message_json, eventrouter, team, channel, metadata):
- channel.set_name(message_json['channel']['name'])
+ channel.set_name(message_json["channel"]["name"])
def process_im_created(message_json, eventrouter, team, channel, metadata):
item = message_json["channel"]
channel = SlackDMChannel(eventrouter, team=team, users=team.users, **item)
team.channels[item["id"]] = channel
- team.buffer_prnt('IM channel created: {}'.format(channel.name))
+ team.buffer_prnt("IM channel created: {}".format(channel.name))
def process_im_open(message_json, eventrouter, team, channel, metadata):
@@ -3545,15 +4211,21 @@ def process_im_open(message_json, eventrouter, team, channel, metadata):
def process_im_close(message_json, eventrouter, team, channel, metadata):
if channel.channel_buffer:
- w.prnt(team.channel_buffer,
- 'IM {} closed by another client or the server'.format(channel.name))
- eventrouter.weechat_controller.unregister_buffer(channel.channel_buffer, False, True)
+ w.prnt(
+ team.channel_buffer,
+ "IM {} closed by another client or the server".format(channel.name),
+ )
+ eventrouter.weechat_controller.unregister_buffer(
+ channel.channel_buffer, False, True
+ )
def process_group_joined(message_json, eventrouter, team, channel, metadata):
item = message_json["channel"]
if item["name"].startswith("mpdm-"):
- channel = SlackMPDMChannel(eventrouter, team.users, team.myidentifier, team=team, **item)
+ channel = SlackMPDMChannel(
+ eventrouter, team.users, team.myidentifier, team=team, **item
+ )
else:
channel = SlackGroupChannel(eventrouter, team=team, **item)
team.channels[item["id"]] = channel
@@ -3563,7 +4235,7 @@ def process_group_joined(message_json, eventrouter, team, channel, metadata):
def process_reaction_added(message_json, eventrouter, team, channel, metadata):
channel = team.channels.get(message_json["item"].get("channel"))
if message_json["item"].get("type") == "message":
- ts = SlackTS(message_json['item']["ts"])
+ ts = SlackTS(message_json["item"]["ts"])
message = channel.messages.get(ts)
if message:
@@ -3576,7 +4248,7 @@ def process_reaction_added(message_json, eventrouter, team, channel, metadata):
def process_reaction_removed(message_json, eventrouter, team, channel, metadata):
channel = team.channels.get(message_json["item"].get("channel"))
if message_json["item"].get("type") == "message":
- ts = SlackTS(message_json['item']["ts"])
+ ts = SlackTS(message_json["item"]["ts"])
message = channel.messages.get(ts)
if message:
@@ -3587,25 +4259,33 @@ def process_reaction_removed(message_json, eventrouter, team, channel, metadata)
def process_subteam_created(subteam_json, eventrouter, team, channel, metadata):
- subteam_json_info = subteam_json['subteam']
- is_member = team.myidentifier in subteam_json_info.get('users', [])
+ subteam_json_info = subteam_json["subteam"]
+ is_member = team.myidentifier in subteam_json_info.get("users", [])
subteam = SlackSubteam(team.identifier, is_member=is_member, **subteam_json_info)
- team.subteams[subteam_json_info['id']] = subteam
+ team.subteams[subteam_json_info["id"]] = subteam
def process_subteam_updated(subteam_json, eventrouter, team, channel, metadata):
- current_subteam_info = team.subteams[subteam_json['subteam']['id']]
- is_member = team.myidentifier in subteam_json['subteam'].get('users', [])
- new_subteam_info = SlackSubteam(team.identifier, is_member=is_member, **subteam_json['subteam'])
- team.subteams[subteam_json['subteam']['id']] = new_subteam_info
+ current_subteam_info = team.subteams[subteam_json["subteam"]["id"]]
+ is_member = team.myidentifier in subteam_json["subteam"].get("users", [])
+ new_subteam_info = SlackSubteam(
+ team.identifier, is_member=is_member, **subteam_json["subteam"]
+ )
+ team.subteams[subteam_json["subteam"]["id"]] = new_subteam_info
if current_subteam_info.is_member != new_subteam_info.is_member:
for channel in team.channels.values():
channel.set_highlights()
- if config.notify_usergroup_handle_updated and current_subteam_info.handle != new_subteam_info.handle:
- message = 'User group {old_handle} has updated its handle to {new_handle} in team {team}.'.format(
- old_handle=current_subteam_info.handle, new_handle=new_subteam_info.handle, team=team.name)
+ if (
+ config.notify_usergroup_handle_updated
+ and current_subteam_info.handle != new_subteam_info.handle
+ ):
+ message = "User group {old_handle} has updated its handle to {new_handle} in team {team}.".format(
+ old_handle=current_subteam_info.handle,
+ new_handle=new_subteam_info.handle,
+ team=team.name,
+ )
team.buffer_prnt(message, message=True)
@@ -3639,16 +4319,22 @@ def process_thread_unsubscribed(message_json, eventrouter, team, channel, metada
###### New module/global methods
def render_formatting(text):
- text = re.sub(r'(^| )\*([^*\n`]+)\*(?=[^\w]|$)',
- r'\1{}*\2*{}'.format(w.color(config.render_bold_as),
- w.color('-' + config.render_bold_as)),
- text,
- flags=re.UNICODE)
- text = re.sub(r'(^| )_([^_\n`]+)_(?=[^\w]|$)',
- r'\1{}_\2_{}'.format(w.color(config.render_italic_as),
- w.color('-' + config.render_italic_as)),
- text,
- flags=re.UNICODE)
+ text = re.sub(
+ r"(^| )\*([^*\n`]+)\*(?=[^\w]|$)",
+ r"\1{}*\2*{}".format(
+ w.color(config.render_bold_as), w.color("-" + config.render_bold_as)
+ ),
+ text,
+ flags=re.UNICODE,
+ )
+ text = re.sub(
+ r"(^| )_([^_\n`]+)_(?=[^\w]|$)",
+ r"\1{}_\2_{}".format(
+ w.color(config.render_italic_as), w.color("-" + config.render_italic_as)
+ ),
+ text,
+ flags=re.UNICODE,
+ )
return text
@@ -3659,17 +4345,19 @@ def linkify_text(message, team, only_users=False, escape_characters=True):
channels = team.get_channel_map()
usergroups = team.generate_usergroup_map()
if escape_characters:
- message = (message
+ message = (
+ message
# Replace IRC formatting chars with Slack formatting chars.
- .replace('\x02', '*')
- .replace('\x1D', '_')
- .replace('\x1F', config.map_underline_to)
+ .replace("\x02", "*")
+ .replace("\x1D", "_")
+ .replace("\x1F", config.map_underline_to)
# Escape chars that have special meaning to Slack. Note that we do not
# (and should not) perform full HTML entity-encoding here.
# See https://api.slack.com/docs/message-formatting for details.
- .replace('&', '&amp;')
- .replace('<', '&lt;')
- .replace('>', '&gt;'))
+ .replace("&", "&amp;")
+ .replace("<", "&lt;")
+ .replace(">", "&gt;")
+ )
def linkify_word(match):
word = match.group(0)
@@ -3686,7 +4374,7 @@ def linkify_text(message, team, only_users=False, escape_characters=True):
return "<#{}|{}>".format(channels[word], name)
return word
- linkify_regex = r'(?:^|(?<=\s))([@#])([\w\(\)\'.-]+)'
+ linkify_regex = r"(?:^|(?<=\s))([@#])([\w\(\)\'.-]+)"
return re.sub(linkify_regex, linkify_word, message, flags=re.UNICODE)
@@ -3705,15 +4393,23 @@ def unfurl_blocks(blocks):
if element["type"] == "button":
elements.append(unfurl_block_element(element["text"]))
else:
- elements.append(colorize_string(config.color_deleted,
- '<<Unsupported block action type "{}">>'.format(element["type"])))
+ elements.append(
+ colorize_string(
+ config.color_deleted,
+ '<<Unsupported block action type "{}">>'.format(
+ element["type"]
+ ),
+ )
+ )
block_text.append(" | ".join(elements))
elif block["type"] == "call":
block_text.append("Join via " + block["call"]["v1"]["join_url"])
elif block["type"] == "divider":
block_text.append("---")
elif block["type"] == "context":
- block_text.append(" | ".join(unfurl_block_element(el) for el in block["elements"]))
+ block_text.append(
+ " | ".join(unfurl_block_element(el) for el in block["elements"])
+ )
elif block["type"] == "image":
if "title" in block:
block_text.append(unfurl_block_element(block["title"]))
@@ -3721,11 +4417,18 @@ def unfurl_blocks(blocks):
elif block["type"] == "rich_text":
continue
else:
- block_text.append(colorize_string(config.color_deleted,
- '<<Unsupported block type "{}">>'.format(block["type"])))
+ block_text.append(
+ colorize_string(
+ config.color_deleted,
+ '<<Unsupported block type "{}">>'.format(block["type"]),
+ )
+ )
dbg('Unsupported block: "{}"'.format(json.dumps(block)), level=4)
except Exception as e:
- dbg("Failed to unfurl block ({}): {}".format(repr(e), json.dumps(block)), level=4)
+ dbg(
+ "Failed to unfurl block ({}): {}".format(repr(e), json.dumps(block)),
+ level=4,
+ )
return block_text
@@ -3782,9 +4485,7 @@ def unfurl_refs(text):
def unhtmlescape(text):
- return text.replace("&lt;", "<") \
- .replace("&gt;", ">") \
- .replace("&amp;", "&")
+ return text.replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&")
def unwrap_attachments(message_json, text_before):
@@ -3793,7 +4494,7 @@ def unwrap_attachments(message_json, text_before):
a = message_json.get("attachments")
if a:
if text_before:
- attachment_texts.append('')
+ attachment_texts.append("")
for attachment in a:
# Attachments should be rendered roughly like:
#
@@ -3801,54 +4502,76 @@ def unwrap_attachments(message_json, text_before):
# $author: (if rest of line is non-empty) $title ($title_link) OR $from_url
# $author: (if no $author on previous line) $text
# $fields
- if 'original_url' in attachment and not config.link_previews:
- continue
+ if "original_url" in attachment and not config.link_previews:
+ continue
t = []
- prepend_title_text = ''
- if 'author_name' in attachment:
- prepend_title_text = attachment['author_name'] + ": "
- if 'pretext' in attachment:
- t.append(attachment['pretext'])
+ prepend_title_text = ""
+ if "author_name" in attachment:
+ prepend_title_text = attachment["author_name"] + ": "
+ if "pretext" in attachment:
+ t.append(attachment["pretext"])
link_shown = False
- title = attachment.get('title')
- title_link = attachment.get('title_link', '')
- if title_link and (title_link in text_before or title_link in text_before_unescaped):
- title_link = ''
+ title = attachment.get("title")
+ title_link = attachment.get("title_link", "")
+ if title_link and (
+ title_link in text_before or title_link in text_before_unescaped
+ ):
+ title_link = ""
link_shown = True
if title and title_link:
- t.append('%s%s (%s)' % (prepend_title_text, title, title_link,))
- prepend_title_text = ''
+ t.append(
+ "%s%s (%s)"
+ % (
+ prepend_title_text,
+ title,
+ title_link,
+ )
+ )
+ prepend_title_text = ""
elif title and not title_link:
- t.append('%s%s' % (prepend_title_text, title,))
- prepend_title_text = ''
- from_url = attachment.get('from_url', '')
- if (from_url not in text_before and from_url not in text_before_unescaped
- and from_url != title_link):
+ t.append(
+ "%s%s"
+ % (
+ prepend_title_text,
+ title,
+ )
+ )
+ prepend_title_text = ""
+ from_url = attachment.get("from_url", "")
+ if (
+ from_url not in text_before
+ and from_url not in text_before_unescaped
+ and from_url != title_link
+ ):
t.append(from_url)
elif from_url:
link_shown = True
atext = attachment.get("text")
if atext:
- tx = re.sub(r' *\n[\n ]+', '\n', atext)
+ tx = re.sub(r" *\n[\n ]+", "\n", atext)
t.append(prepend_title_text + tx)
- prepend_title_text = ''
+ prepend_title_text = ""
blocks = attachment.get("blocks", [])
t.extend(unfurl_blocks(blocks))
- image_url = attachment.get('image_url', '')
- if (image_url not in text_before and image_url not in text_before_unescaped
- and image_url != from_url and image_url != title_link):
+ image_url = attachment.get("image_url", "")
+ if (
+ image_url not in text_before
+ and image_url not in text_before_unescaped
+ and image_url != from_url
+ and image_url != title_link
+ ):
t.append(image_url)
elif image_url:
link_shown = True
for field in attachment.get("fields", []):
- if field.get('title'):
- t.append('{}: {}'.format(field['title'], field['value']))
+ if field.get("title"):
+ t.append("{}: {}".format(field["title"], field["value"]))
else:
- t.append(field['value'])
+ t.append(field["value"])
files = unwrap_files(attachment, None)
if files:
@@ -3859,97 +4582,112 @@ def unwrap_attachments(message_json, text_before):
ts = attachment.get("ts")
if ts:
ts_int = ts if type(ts) == int else SlackTS(ts).major
- time_string = ''
+ time_string = ""
if date.today() - date.fromtimestamp(ts_int) <= timedelta(days=1):
- time_string = ' at {time}'
- timestamp_formatted = resolve_ref('!date^{}^{{date_short_pretty}}{}'
- .format(ts_int, time_string)).capitalize()
- footer += ' | {}'.format(timestamp_formatted)
+ time_string = " at {time}"
+ timestamp_formatted = resolve_ref(
+ "!date^{}^{{date_short_pretty}}{}".format(ts_int, time_string)
+ ).capitalize()
+ footer += " | {}".format(timestamp_formatted)
t.append(footer)
fallback = attachment.get("fallback")
if t == [] and fallback and not link_shown:
t.append(fallback)
if t:
- lines = [line for part in t for line in part.strip().split("\n") if part]
- prefix = '|'
+ lines = [
+ line for part in t for line in part.strip().split("\n") if part
+ ]
+ prefix = "|"
line_color = None
- color = attachment.get('color')
+ color = attachment.get("color")
if color and config.colorize_attachments != "none":
- weechat_color = w.info_get("color_rgb2term", str(int(color.lstrip("#"), 16)))
+ weechat_color = w.info_get(
+ "color_rgb2term", str(int(color.lstrip("#"), 16))
+ )
if config.colorize_attachments == "prefix":
prefix = colorize_string(weechat_color, prefix)
elif config.colorize_attachments == "all":
line_color = weechat_color
attachment_texts.extend(
- colorize_string(line_color, "{} {}".format(prefix, line))
- for line in lines)
+ colorize_string(line_color, "{} {}".format(prefix, line))
+ for line in lines
+ )
return "\n".join(attachment_texts)
def unwrap_files(message_json, text_before):
files_texts = []
- for f in message_json.get('files', []):
- if f.get('mode', '') == 'tombstone':
- text = colorize_string(config.color_deleted, '(This file was deleted.)')
- elif f.get('mode', '') == 'hidden_by_limit':
- text = colorize_string(config.color_deleted, '(This file is hidden because the workspace has passed its storage limit.)')
- elif f.get('url_private', None) is not None and f.get('title', None) is not None:
- text = '{} ({})'.format(f['url_private'], f['title'])
+ for f in message_json.get("files", []):
+ if f.get("mode", "") == "tombstone":
+ text = colorize_string(config.color_deleted, "(This file was deleted.)")
+ elif f.get("mode", "") == "hidden_by_limit":
+ text = colorize_string(
+ config.color_deleted,
+ "(This file is hidden because the workspace has passed its storage limit.)",
+ )
+ elif (
+ f.get("url_private", None) is not None and f.get("title", None) is not None
+ ):
+ text = "{} ({})".format(f["url_private"], f["title"])
else:
- dbg('File {} has unrecognized mode {}'.format(f['id'], f['mode']), 5)
- text = colorize_string(config.color_deleted, '(This file cannot be handled.)')
+ dbg("File {} has unrecognized mode {}".format(f["id"], f["mode"]), 5)
+ text = colorize_string(
+ config.color_deleted, "(This file cannot be handled.)"
+ )
files_texts.append(text)
if text_before:
- files_texts.insert(0, '')
+ files_texts.insert(0, "")
return "\n".join(files_texts)
def resolve_ref(ref):
- if ref in ['!channel', '!everyone', '!group', '!here']:
- return ref.replace('!', '@')
+ if ref in ["!channel", "!everyone", "!group", "!here"]:
+ return ref.replace("!", "@")
for team in EVENTROUTER.teams.values():
- if ref.startswith('@'):
+ if ref.startswith("@"):
user = team.users.get(ref[1:])
if user:
- suffix = config.external_user_suffix if user.is_external else ''
- return '@{}{}'.format(user.name, suffix)
- elif ref.startswith('#'):
+ suffix = config.external_user_suffix if user.is_external else ""
+ return "@{}{}".format(user.name, suffix)
+ elif ref.startswith("#"):
channel = team.channels.get(ref[1:])
if channel:
return channel.name
- elif ref.startswith('!subteam'):
- _, subteam_id = ref.split('^')
+ elif ref.startswith("!subteam"):
+ _, subteam_id = ref.split("^")
subteam = team.subteams.get(subteam_id)
if subteam:
return subteam.handle
elif ref.startswith("!date"):
- parts = ref.split('^')
+ parts = ref.split("^")
ref_datetime = datetime.fromtimestamp(int(parts[1]))
- link_suffix = ' ({})'.format(parts[3]) if len(parts) > 3 else ''
+ link_suffix = " ({})".format(parts[3]) if len(parts) > 3 else ""
token_to_format = {
- 'date_num': '%Y-%m-%d',
- 'date': '%B %d, %Y',
- 'date_short': '%b %d, %Y',
- 'date_long': '%A, %B %d, %Y',
- 'time': '%H:%M',
- 'time_secs': '%H:%M:%S'
+ "date_num": "%Y-%m-%d",
+ "date": "%B %d, %Y",
+ "date_short": "%b %d, %Y",
+ "date_long": "%A, %B %d, %Y",
+ "time": "%H:%M",
+ "time_secs": "%H:%M:%S",
}
def replace_token(match):
token = match.group(1)
- if token.startswith('date_') and token.endswith('_pretty'):
+ if token.startswith("date_") and token.endswith("_pretty"):
if ref_datetime.date() == date.today():
- return 'today'
+ return "today"
elif ref_datetime.date() == date.today() - timedelta(days=1):
- return 'yesterday'
+ return "yesterday"
elif ref_datetime.date() == date.today() + timedelta(days=1):
- return 'tomorrow'
+ return "tomorrow"
else:
- token = token.replace('_pretty', '')
+ token = token.replace("_pretty", "")
if token in token_to_format:
- return decode_from_utf8(ref_datetime.strftime(token_to_format[token]))
+ return decode_from_utf8(
+ ref_datetime.strftime(token_to_format[token])
+ )
else:
return match.group(0)
@@ -3971,39 +4709,46 @@ def create_user_status_string(profile):
def create_reaction_string(reaction, myidentifier):
if config.show_reaction_nicks:
- nicks = [resolve_ref('@{}'.format(user)) for user in reaction['users']]
- users = '({})'.format(','.join(nicks))
+ nicks = [resolve_ref("@{}".format(user)) for user in reaction["users"]]
+ users = "({})".format(",".join(nicks))
else:
- users = len(reaction['users'])
- reaction_string = ':{}:{}'.format(reaction['name'], users)
- if myidentifier in reaction['users']:
- return colorize_string(config.color_reaction_suffix_added_by_you, reaction_string,
- reset_color=config.color_reaction_suffix)
+ users = len(reaction["users"])
+ reaction_string = ":{}:{}".format(reaction["name"], users)
+ if myidentifier in reaction["users"]:
+ return colorize_string(
+ config.color_reaction_suffix_added_by_you,
+ reaction_string,
+ reset_color=config.color_reaction_suffix,
+ )
else:
return reaction_string
def create_reactions_string(reactions, myidentifier):
- reactions_with_users = [r for r in reactions if len(r['users']) > 0]
- reactions_string = ' '.join(create_reaction_string(r, myidentifier) for r in reactions_with_users)
+ reactions_with_users = [r for r in reactions if len(r["users"]) > 0]
+ reactions_string = " ".join(
+ create_reaction_string(r, myidentifier) for r in reactions_with_users
+ )
if reactions_string:
- return ' ' + colorize_string(config.color_reaction_suffix, '[{}]'.format(reactions_string))
+ return " " + colorize_string(
+ config.color_reaction_suffix, "[{}]".format(reactions_string)
+ )
else:
- return ''
+ return ""
def hdata_line_ts(line_pointer):
- data = w.hdata_pointer(hdata.line, line_pointer, 'data')
- for i in range(w.hdata_integer(hdata.line_data, data, 'tags_count')):
- tag = w.hdata_string(hdata.line_data, data, '{}|tags_array'.format(i))
- if tag.startswith('slack_ts_'):
+ data = w.hdata_pointer(hdata.line, line_pointer, "data")
+ for i in range(w.hdata_integer(hdata.line_data, data, "tags_count")):
+ tag = w.hdata_string(hdata.line_data, data, "{}|tags_array".format(i))
+ if tag.startswith("slack_ts_"):
return SlackTS(tag[9:])
return None
def modify_buffer_line(buffer_pointer, ts, new_text):
- own_lines = w.hdata_pointer(hdata.buffer, buffer_pointer, 'own_lines')
- line_pointer = w.hdata_pointer(hdata.lines, own_lines, 'last_line')
+ own_lines = w.hdata_pointer(hdata.buffer, buffer_pointer, "own_lines")
+ line_pointer = w.hdata_pointer(hdata.lines, own_lines, "last_line")
# Find the last line with this ts
is_last_line = True
@@ -4022,60 +4767,70 @@ def modify_buffer_line(buffer_pointer, ts, new_text):
return w.WEECHAT_RC_OK
if is_last_line:
- lines = new_text.split('\n')
+ lines = new_text.split("\n")
extra_lines_count = len(lines) - len(pointers)
if extra_lines_count > 0:
- line_data = w.hdata_pointer(hdata.line, pointers[0], 'data')
- tags_count = w.hdata_integer(hdata.line_data, line_data, 'tags_count')
- tags = [w.hdata_string(hdata.line_data, line_data, '{}|tags_array'.format(i))
- for i in range(tags_count)]
+ line_data = w.hdata_pointer(hdata.line, pointers[0], "data")
+ tags_count = w.hdata_integer(hdata.line_data, line_data, "tags_count")
+ tags = [
+ w.hdata_string(hdata.line_data, line_data, "{}|tags_array".format(i))
+ for i in range(tags_count)
+ ]
tags = tags_set_notify_none(tags)
- tags_str = ','.join(tags)
- last_read_line = w.hdata_pointer(hdata.lines, own_lines, 'last_read_line')
+ tags_str = ",".join(tags)
+ last_read_line = w.hdata_pointer(hdata.lines, own_lines, "last_read_line")
should_set_unread = last_read_line == pointers[-1]
# Insert new lines to match the number of lines in the message
w.buffer_set(buffer_pointer, "print_hooks_enabled", "0")
for _ in range(extra_lines_count):
w.prnt_date_tags(buffer_pointer, ts.major, tags_str, " \t ")
- pointers.append(w.hdata_pointer(hdata.lines, own_lines, 'last_line'))
+ pointers.append(w.hdata_pointer(hdata.lines, own_lines, "last_line"))
if should_set_unread:
w.buffer_set(buffer_pointer, "unread", "")
w.buffer_set(buffer_pointer, "print_hooks_enabled", "1")
else:
# Split the message into at most the number of existing lines as we can't insert new lines
- lines = new_text.split('\n', len(pointers) - 1)
+ lines = new_text.split("\n", len(pointers) - 1)
# Replace newlines to prevent garbled lines in bare display mode
- lines = [line.replace('\n', ' | ') for line in lines]
+ lines = [line.replace("\n", " | ") for line in lines]
# Extend lines in case the new message is shorter than the old as we can't delete lines
- lines += [''] * (len(pointers) - len(lines))
+ lines += [""] * (len(pointers) - len(lines))
for pointer, line in zip(pointers, lines):
- data = w.hdata_pointer(hdata.line, pointer, 'data')
+ data = w.hdata_pointer(hdata.line, pointer, "data")
w.hdata_update(hdata.line_data, data, {"message": line})
return w.WEECHAT_RC_OK
def nick_from_profile(profile, username):
- full_name = profile.get('real_name') or username
+ full_name = profile.get("real_name") or username
if config.use_full_names:
nick = full_name
else:
- nick = profile.get('display_name') or full_name
- return nick.replace(' ', '')
+ nick = profile.get("display_name") or full_name
+ return nick.replace(" ", "")
def format_nick(nick, previous_nick=None):
if nick == previous_nick:
- nick = w.config_string(w.config_get('weechat.look.prefix_same_nick')) or nick
- nick_prefix = w.config_string(w.config_get('weechat.look.nick_prefix'))
- nick_prefix_color_name = w.config_string(w.config_get('weechat.color.chat_nick_prefix'))
+ nick = w.config_string(w.config_get("weechat.look.prefix_same_nick")) or nick
+ nick_prefix = w.config_string(w.config_get("weechat.look.nick_prefix"))
+ nick_prefix_color_name = w.config_string(
+ w.config_get("weechat.color.chat_nick_prefix")
+ )
- nick_suffix = w.config_string(w.config_get('weechat.look.nick_suffix'))
- nick_suffix_color_name = w.config_string(w.config_get('weechat.color.chat_nick_prefix'))
- return colorize_string(nick_prefix_color_name, nick_prefix) + nick + colorize_string(nick_suffix_color_name, nick_suffix)
+ nick_suffix = w.config_string(w.config_get("weechat.look.nick_suffix"))
+ nick_suffix_color_name = w.config_string(
+ w.config_get("weechat.color.chat_nick_prefix")
+ )
+ return (
+ colorize_string(nick_prefix_color_name, nick_prefix)
+ + nick
+ + colorize_string(nick_suffix_color_name, nick_suffix)
+ )
def tags_set_notify_none(tags):
@@ -4085,7 +4840,15 @@ def tags_set_notify_none(tags):
return tags
-def tag(ts, tagset=None, user=None, self_msg=False, backlog=False, no_log=False, extra_tags=None):
+def tag(
+ ts,
+ tagset=None,
+ user=None,
+ self_msg=False,
+ backlog=False,
+ no_log=False,
+ extra_tags=None,
+):
tagsets = {
"team_info": ["no_highlight", "log3"],
"team_message": ["irc_privmsg", "notify_message", "log1"],
@@ -4107,14 +4870,16 @@ def tag(ts, tagset=None, user=None, self_msg=False, backlog=False, no_log=False,
tags += ["logger_backlog"]
if no_log:
tags += ["no_log"]
- tags = [tag for tag in tags if not tag.startswith("log") or tag == "logger_backlog"]
+ tags = [
+ tag for tag in tags if not tag.startswith("log") or tag == "logger_backlog"
+ ]
if extra_tags:
tags += extra_tags
return ",".join(OrderedDict.fromkeys(tags))
def set_own_presence_active(team):
- slackbot = team.get_channel_map()['Slackbot']
+ slackbot = team.get_channel_map()["Slackbot"]
channel = team.channels[slackbot]
request = {"type": "typing", "channel": channel.identifier}
channel.team.send_to_websocket(request, expect_reply=False)
@@ -4129,14 +4894,19 @@ def invite_command_cb(data, current_buffer, args):
team = EVENTROUTER.weechat_controller.buffers[current_buffer].team
split_args = args.split()[1:]
if not split_args:
- w.prnt('', 'Too few arguments for command "/invite" (help on command: /help invite)')
+ w.prnt(
+ "",
+ 'Too few arguments for command "/invite" (help on command: /help invite)',
+ )
return w.WEECHAT_RC_OK_EAT
- if split_args[-1].startswith("#") or split_args[-1].startswith(config.group_name_prefix):
+ if split_args[-1].startswith("#") or split_args[-1].startswith(
+ config.group_name_prefix
+ ):
nicks = split_args[:-1]
channel = team.channels.get(team.get_channel_map().get(split_args[-1]))
if not nicks or not channel:
- w.prnt('', '{}: No such nick/channel'.format(split_args[-1]))
+ w.prnt("", "{}: No such nick/channel".format(split_args[-1]))
return w.WEECHAT_RC_OK_EAT
else:
nicks = split_args
@@ -4145,14 +4915,19 @@ def invite_command_cb(data, current_buffer, args):
all_users = team.get_username_map()
users = set()
for nick in nicks:
- user = all_users.get(nick.lstrip('@'))
+ user = all_users.get(nick.lstrip("@"))
if not user:
- w.prnt('', 'ERROR: Unknown user: {}'.format(nick))
+ w.prnt("", "ERROR: Unknown user: {}".format(nick))
return w.WEECHAT_RC_OK_EAT
users.add(user)
- s = SlackRequest(team, "conversations.invite", {"channel": channel.identifier, "users": ",".join(users)},
- channel=channel, metadata={"nicks": nicks})
+ s = SlackRequest(
+ team,
+ "conversations.invite",
+ {"channel": channel.identifier, "users": ",".join(users)},
+ channel=channel,
+ metadata={"nicks": nicks},
+ )
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK_EAT
@@ -4168,24 +4943,28 @@ def part_command_cb(data, current_buffer, args):
channel = "".join(args[1:])
if channel in cmap:
buffer_ptr = team.channels[cmap[channel]].channel_buffer
- e.weechat_controller.unregister_buffer(buffer_ptr, update_remote=True, close_buffer=True)
+ e.weechat_controller.unregister_buffer(
+ buffer_ptr, update_remote=True, close_buffer=True
+ )
else:
w.prnt(team.channel_buffer, "{}: No such channel".format(channel))
else:
- e.weechat_controller.unregister_buffer(current_buffer, update_remote=True, close_buffer=True)
+ e.weechat_controller.unregister_buffer(
+ current_buffer, update_remote=True, close_buffer=True
+ )
return w.WEECHAT_RC_OK_EAT
def parse_topic_command(command):
- _, _, args = command.partition(' ')
- if args.startswith('#'):
- channel_name, _, topic_arg = args.partition(' ')
+ _, _, args = command.partition(" ")
+ if args.startswith("#"):
+ channel_name, _, topic_arg = args.partition(" ")
else:
channel_name = None
topic_arg = args
- if topic_arg == '-delete':
- topic = ''
+ if topic_arg == "-delete":
+ topic = ""
elif topic_arg:
topic = topic_arg
else:
@@ -4214,11 +4993,17 @@ def topic_command_cb(data, current_buffer, command):
return w.WEECHAT_RC_OK_EAT
if topic is None:
- w.prnt(channel.channel_buffer,
- 'Topic for {} is "{}"'.format(channel.name, channel.render_topic()))
+ w.prnt(
+ channel.channel_buffer,
+ 'Topic for {} is "{}"'.format(channel.name, channel.render_topic()),
+ )
else:
- s = SlackRequest(team, "conversations.setTopic",
- {"channel": channel.identifier, "topic": linkify_text(topic, team)}, channel=channel)
+ s = SlackRequest(
+ team,
+ "conversations.setTopic",
+ {"channel": channel.identifier, "topic": linkify_text(topic, team)},
+ channel=channel,
+ )
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK_EAT
@@ -4235,11 +5020,12 @@ def whois_command_cb(data, current_buffer, command):
w.prnt(current_buffer, "Not enough arguments")
return w.WEECHAT_RC_OK_EAT
user = args[1]
- if (user.startswith('@')):
+ if user.startswith("@"):
user = user[1:]
team = EVENTROUTER.weechat_controller.buffers[current_buffer].team
u = team.users.get(team.get_username_map().get(user))
if u:
+
def print_profile(field):
value = u.profile.get(field)
if value:
@@ -4254,10 +5040,10 @@ def whois_command_cb(data, current_buffer, command):
team.buffer_prnt("[{}]: username: {}".format(user, u.username))
team.buffer_prnt("[{}]: id: {}".format(user, u.identifier))
- print_profile('title')
- print_profile('email')
- print_profile('phone')
- print_profile('skype')
+ print_profile("title")
+ print_profile("email")
+ print_profile("phone")
+ print_profile("skype")
else:
team.buffer_prnt("[{}]: No such user".format(user))
return w.WEECHAT_RC_OK_EAT
@@ -4267,8 +5053,8 @@ def whois_command_cb(data, current_buffer, command):
@utf8_decode
def me_command_cb(data, current_buffer, args):
channel = EVENTROUTER.weechat_controller.buffers[current_buffer]
- message = args.split(' ', 1)[1]
- channel.send_message(message, subtype='me_message')
+ message = args.split(" ", 1)[1]
+ channel.send_message(message, subtype="me_message")
return w.WEECHAT_RC_OK_EAT
@@ -4296,7 +5082,9 @@ def command_register(data, current_buffer, args):
else:
nothirdparty = args == "-nothirdparty"
code = "" if nothirdparty else args
- redirect_uri = quote(REDIRECT_URI_NOTHIRDPARTY if nothirdparty else REDIRECT_URI_GITHUB, safe='')
+ redirect_uri = quote(
+ REDIRECT_URI_NOTHIRDPARTY if nothirdparty else REDIRECT_URI_GITHUB, safe=""
+ )
if not code:
if nothirdparty:
@@ -4305,17 +5093,23 @@ def command_register(data, current_buffer, args):
else:
nothirdparty_note = "\nNote that by default GitHub Pages will see a temporary code used to create your token (but not the token itself). If you're worried about this, you can use the -nothirdparty option, though the process will be a bit less user friendly."
last_step = "The web page will show a command in the form `/slack register <code>`. Run this command in weechat."
- message = textwrap.dedent("""
+ message = (
+ textwrap.dedent(
+ """
### Connecting to a Slack team with OAuth ###{}
1) Paste this link into a browser: https://slack.com/oauth/authorize?client_id={}&scope=client&redirect_uri={}
2) Select the team you wish to access from wee-slack in your browser. If you want to add multiple teams, you will have to repeat this whole process for each team.
3) Click "Authorize" in the browser.
If you get a message saying you are not authorized to install wee-slack, the team has restricted Slack app installation and you will have to request it from an admin. To do that, go to https://my.slack.com/apps/A1HSZ9V8E-wee-slack and click "Request to Install".
4) {}
- """).strip().format(nothirdparty_note, CLIENT_ID, redirect_uri, last_step)
+ """
+ )
+ .strip()
+ .format(nothirdparty_note, CLIENT_ID, redirect_uri, last_step)
+ )
w.prnt("", "\n" + message)
return w.WEECHAT_RC_OK_EAT
- elif code.startswith('xox'):
+ elif code.startswith("xox"):
add_token(code)
return w.WEECHAT_RC_OK_EAT
@@ -4323,64 +5117,79 @@ def command_register(data, current_buffer, args):
"https://slack.com/api/oauth.access?"
"client_id={}&client_secret={}&redirect_uri={}&code={}"
).format(CLIENT_ID, CLIENT_SECRET, redirect_uri, code)
- params = {'useragent': 'wee_slack {}'.format(SCRIPT_VERSION)}
- w.hook_process_hashtable('url:', params, config.slack_timeout, "", "")
- w.hook_process_hashtable("url:{}".format(uri), params, config.slack_timeout, "register_callback", "")
+ params = {"useragent": "wee_slack {}".format(SCRIPT_VERSION)}
+ w.hook_process_hashtable("url:", params, config.slack_timeout, "", "")
+ w.hook_process_hashtable(
+ "url:{}".format(uri), params, config.slack_timeout, "register_callback", ""
+ )
return w.WEECHAT_RC_OK_EAT
-command_register.completion = '-nothirdparty %-'
+
+command_register.completion = "-nothirdparty %-"
@utf8_decode
def register_callback(data, command, return_code, out, err):
if return_code != 0:
- w.prnt("", "ERROR: problem when trying to get Slack OAuth token. Got return code {}. Err: {}".format(return_code, err))
+ w.prnt(
+ "",
+ "ERROR: problem when trying to get Slack OAuth token. Got return code {}. Err: {}".format(
+ return_code, err
+ ),
+ )
w.prnt("", "Check the network or proxy settings")
return w.WEECHAT_RC_OK_EAT
if len(out) <= 0:
- w.prnt("", "ERROR: problem when trying to get Slack OAuth token. Got 0 length answer. Err: {}".format(err))
+ w.prnt(
+ "",
+ "ERROR: problem when trying to get Slack OAuth token. Got 0 length answer. Err: {}".format(
+ err
+ ),
+ )
w.prnt("", "Check the network or proxy settings")
return w.WEECHAT_RC_OK_EAT
d = json.loads(out)
if not d["ok"]:
- w.prnt("",
- "ERROR: Couldn't get Slack OAuth token: {}".format(d['error']))
+ w.prnt("", "ERROR: Couldn't get Slack OAuth token: {}".format(d["error"]))
return w.WEECHAT_RC_OK_EAT
- add_token(d['access_token'], d['team_name'])
+ add_token(d["access_token"], d["team_name"])
return w.WEECHAT_RC_OK_EAT
def add_token(token, team_name=None):
- if config.is_default('slack_api_token'):
- w.config_set_plugin('slack_api_token', token)
+ if config.is_default("slack_api_token"):
+ w.config_set_plugin("slack_api_token", token)
else:
# Add new token to existing set, joined by comma.
- existing_tokens = config.get_string('slack_api_token')
+ existing_tokens = config.get_string("slack_api_token")
if token in existing_tokens:
- print_error('This token is already registered')
+ print_error("This token is already registered")
return
- w.config_set_plugin('slack_api_token', ','.join([existing_tokens, token]))
+ w.config_set_plugin("slack_api_token", ",".join([existing_tokens, token]))
if team_name:
- w.prnt("", "Success! Added team \"{}\"".format(team_name))
+ w.prnt("", 'Success! Added team "{}"'.format(team_name))
else:
w.prnt("", "Success! Added token")
w.prnt("", "Please reload wee-slack with: /python reload slack")
- w.prnt("", "If you want to add another team you can repeat this process from step 1 before reloading wee-slack.")
+ w.prnt(
+ "",
+ "If you want to add another team you can repeat this process from step 1 before reloading wee-slack.",
+ )
@slack_buffer_or_ignore
@utf8_decode
def msg_command_cb(data, current_buffer, args):
aargs = args.split(None, 2)
- who = aargs[1].lstrip('@')
+ who = aargs[1].lstrip("@")
if who == "*":
who = EVENTROUTER.weechat_controller.buffers[current_buffer].name
else:
- join_query_command_cb(data, current_buffer, '/query ' + who)
+ join_query_command_cb(data, current_buffer, "/query " + who)
if len(aargs) > 2:
message = aargs[2]
@@ -4398,7 +5207,9 @@ def print_team_items_info(team, header, items, extra_info_function):
max_name_length = max(len(item.name) for item in items)
for item in sorted(items, key=lambda item: item.name.lower()):
extra_info = extra_info_function(item)
- team.buffer_prnt(" {:<{}}({})".format(item.name, max_name_length + 2, extra_info))
+ team.buffer_prnt(
+ " {:<{}}({})".format(item.name, max_name_length + 2, extra_info)
+ )
return w.WEECHAT_RC_OK_EAT
@@ -4406,6 +5217,7 @@ def print_users_info(team, header, users):
def extra_info_function(user):
external_text = ", external" if user.is_external else ""
return user.presence + external_text
+
return print_team_items_info(team, header, users, extra_info_function)
@@ -4430,7 +5242,12 @@ def command_channels(data, current_buffer, args):
List the channels in the current team.
"""
team = EVENTROUTER.weechat_controller.buffers[current_buffer].team
- channels = [channel for channel in team.channels.values() if channel.type not in ['im', 'mpim']]
+ channels = [
+ channel
+ for channel in team.channels.values()
+ if channel.type not in ["im", "mpim"]
+ ]
+
def extra_info_function(channel):
if channel.active:
return "member"
@@ -4438,6 +5255,7 @@ def command_channels(data, current_buffer, args):
return "archived"
else:
return "not a member"
+
return print_team_items_info(team, "Channels", channels, extra_info_function)
@@ -4465,20 +5283,29 @@ def command_usergroups(data, current_buffer, args):
usergroup_key = usergroups.get(args)
if usergroup_key:
- s = SlackRequest(team, "usergroups.users.list", {"usergroup": usergroup_key},
- metadata={'usergroup_handle': args})
+ s = SlackRequest(
+ team,
+ "usergroups.users.list",
+ {"usergroup": usergroup_key},
+ metadata={"usergroup_handle": args},
+ )
EVENTROUTER.receive(s)
elif args:
- w.prnt('', 'ERROR: Unknown usergroup handle: {}'.format(args))
+ w.prnt("", "ERROR: Unknown usergroup handle: {}".format(args))
return w.WEECHAT_RC_ERROR
else:
+
def extra_info_function(subteam):
- is_member = 'member' if subteam.is_member else 'not a member'
- return '{}, {}'.format(subteam.handle, is_member)
- return print_team_items_info(team, "Usergroups", team.subteams.values(), extra_info_function)
+ is_member = "member" if subteam.is_member else "not a member"
+ return "{}, {}".format(subteam.handle, is_member)
+
+ return print_team_items_info(
+ team, "Usergroups", team.subteams.values(), extra_info_function
+ )
return w.WEECHAT_RC_OK_EAT
-command_usergroups.completion = '%(usergroups) %-'
+
+command_usergroups.completion = "%(usergroups) %-"
@slack_buffer_required
@@ -4489,21 +5316,26 @@ def command_talk(data, current_buffer, args):
Open a chat with the specified user(s).
"""
if not args:
- w.prnt('', 'Usage: /slack talk <user>[,<user2>[,<user3>...]]')
+ w.prnt("", "Usage: /slack talk <user>[,<user2>[,<user3>...]]")
return w.WEECHAT_RC_ERROR
- return join_query_command_cb(data, current_buffer, '/query ' + args)
+ return join_query_command_cb(data, current_buffer, "/query " + args)
+
-command_talk.completion = '%(nicks)'
+command_talk.completion = "%(nicks)"
@slack_buffer_or_ignore
@utf8_decode
def join_query_command_cb(data, current_buffer, args):
team = EVENTROUTER.weechat_controller.buffers[current_buffer].team
- split_args = args.split(' ', 1)
+ split_args = args.split(" ", 1)
if len(split_args) < 2 or not split_args[1]:
- w.prnt('', 'Too few arguments for command "{}" (help on command: /help {})'
- .format(split_args[0], split_args[0].lstrip('/')))
+ w.prnt(
+ "",
+ 'Too few arguments for command "{}" (help on command: /help {})'.format(
+ split_args[0], split_args[0].lstrip("/")
+ ),
+ )
return w.WEECHAT_RC_OK_EAT
query = split_args[1]
@@ -4512,33 +5344,37 @@ def join_query_command_cb(data, current_buffer, args):
# If the channel doesn't exist, try finding a DM or MPDM instead
if not channel:
- if query.startswith('#'):
- w.prnt('', 'ERROR: Unknown channel: {}'.format(query))
+ if query.startswith("#"):
+ w.prnt("", "ERROR: Unknown channel: {}".format(query))
return w.WEECHAT_RC_OK_EAT
# Get the IDs of the users
all_users = team.get_username_map()
users = set()
- for username in query.split(','):
- user = all_users.get(username.lstrip('@'))
+ for username in query.split(","):
+ user = all_users.get(username.lstrip("@"))
if not user:
- w.prnt('', 'ERROR: Unknown user: {}'.format(username))
+ w.prnt("", "ERROR: Unknown user: {}".format(username))
return w.WEECHAT_RC_OK_EAT
users.add(user)
if users:
if len(users) > 1:
- channel_type = 'mpim'
+ channel_type = "mpim"
# Add the current user since MPDMs include them as a member
users.add(team.myidentifier)
else:
- channel_type = 'im'
+ channel_type = "im"
channel = team.find_channel_by_members(users, channel_type=channel_type)
# If the DM or MPDM doesn't exist, create it
if not channel:
- s = SlackRequest(team, team.slack_api_translator[channel_type]['join'], {'users': ','.join(users)})
+ s = SlackRequest(
+ team,
+ team.slack_api_translator[channel_type]["join"],
+ {"users": ",".join(users)},
+ )
EVENTROUTER.receive(s)
if channel:
@@ -4569,7 +5405,8 @@ def command_create(data, current_buffer, args):
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK_EAT
-command_create.completion = '-private'
+
+command_create.completion = "-private"
@slack_buffer_required
@@ -4580,9 +5417,10 @@ def command_showmuted(data, current_buffer, args):
List the muted channels in the current team.
"""
team = EVENTROUTER.weechat_controller.buffers[current_buffer].team
- muted_channels = [team.channels[key].name
- for key in team.muted_channels if key in team.channels]
- team.buffer_prnt("Muted channels: {}".format(', '.join(muted_channels)))
+ muted_channels = [
+ team.channels[key].name for key in team.muted_channels if key in team.channels
+ ]
+ team.buffer_prnt("Muted channels: {}".format(", ".join(muted_channels)))
return w.WEECHAT_RC_OK_EAT
@@ -4597,7 +5435,7 @@ def command_thread(data, current_buffer, args):
channel = EVENTROUTER.weechat_controller.buffers[current_buffer]
if not isinstance(channel, SlackChannelCommon):
- print_error('/thread can not be used in the team buffer, only in a channel')
+ print_error("/thread can not be used in the team buffer, only in a channel")
return w.WEECHAT_RC_ERROR
message = channel.message_from_hash(args)
@@ -4608,14 +5446,17 @@ def command_thread(data, current_buffer, args):
if message:
message.open_thread(switch=config.switch_buffer_on_join)
elif args:
- print_error("Invalid id given, must be an existing id or a number greater " +
- "than 0 and less than the number of thread messages in the channel")
+ print_error(
+ "Invalid id given, must be an existing id or a number greater "
+ + "than 0 and less than the number of thread messages in the channel"
+ )
else:
print_error("No threads found in channel")
return w.WEECHAT_RC_OK_EAT
-command_thread.completion = '%(threads) %-'
+
+command_thread.completion = "%(threads) %-"
def subscribe_helper(current_buffer, args, usage, api):
@@ -4633,7 +5474,11 @@ def subscribe_helper(current_buffer, args, usage, api):
return w.WEECHAT_RC_OK_EAT
last_read = next(reversed(message.submessages), message.ts)
- post_data = {"channel": channel.identifier, "thread_ts": message.ts, "last_read": last_read}
+ post_data = {
+ "channel": channel.identifier,
+ "thread_ts": message.ts,
+ "last_read": last_read,
+ }
s = SlackRequest(team, api, post_data, channel=channel)
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK_EAT
@@ -4649,9 +5494,15 @@ def command_subscribe(data, current_buffer, args):
This command only works when using a session token, see the readme: https://github.com/wee-slack/wee-slack#4-add-your-slack-api-tokens
"""
- return subscribe_helper(current_buffer, args, 'Usage: /slack subscribe <thread>', "subscriptions.thread.add")
+ return subscribe_helper(
+ current_buffer,
+ args,
+ "Usage: /slack subscribe <thread>",
+ "subscriptions.thread.add",
+ )
+
-command_subscribe.completion = '%(threads) %-'
+command_subscribe.completion = "%(threads) %-"
@slack_buffer_required
@@ -4665,9 +5516,15 @@ def command_unsubscribe(data, current_buffer, args):
This command only works when using a session token, see the readme: https://github.com/wee-slack/wee-slack#4-add-your-slack-api-tokens
"""
- return subscribe_helper(current_buffer, args, 'Usage: /slack unsubscribe <thread>', "subscriptions.thread.remove")
+ return subscribe_helper(
+ current_buffer,
+ args,
+ "Usage: /slack unsubscribe <thread>",
+ "subscriptions.thread.remove",
+ )
+
-command_unsubscribe.completion = '%(threads) %-'
+command_unsubscribe.completion = "%(threads) %-"
@slack_buffer_required
@@ -4703,7 +5560,10 @@ def command_reply(data, current_buffer, args):
try:
msg_id, text = args.split(None, 1)
except ValueError:
- w.prnt('', 'Usage (when in a channel buffer): /reply [-alsochannel] <count/message_id> <message>')
+ w.prnt(
+ "",
+ "Usage (when in a channel buffer): /reply [-alsochannel] <count/message_id> <message>",
+ )
return w.WEECHAT_RC_OK_EAT
message = channel.message_from_hash_or_index(msg_id)
@@ -4716,10 +5576,13 @@ def command_reply(data, current_buffer, args):
elif message:
parent_id = str(message.ts)
- channel.send_message(text, request_dict_ext={'thread_ts': parent_id, 'reply_broadcast': broadcast})
+ channel.send_message(
+ text, request_dict_ext={"thread_ts": parent_id, "reply_broadcast": broadcast}
+ )
return w.WEECHAT_RC_OK_EAT
-command_reply.completion = '%(threads)|-alsochannel %(threads)'
+
+command_reply.completion = "%(threads)|-alsochannel %(threads)"
@slack_buffer_required
@@ -4737,7 +5600,8 @@ def command_rehistory(data, current_buffer, args):
channel.reprint_messages(force_render=True)
return w.WEECHAT_RC_OK_EAT
-command_rehistory.completion = '-remote'
+
+command_rehistory.completion = "-remote"
@slack_buffer_required
@@ -4748,7 +5612,7 @@ def command_hide(data, current_buffer, args):
Hide the current channel if it is marked as distracting.
"""
channel = EVENTROUTER.weechat_controller.buffers[current_buffer]
- name = channel.formatted_name(style='long_default')
+ name = channel.formatted_name(style="long_default")
if name in config.distracting_channels:
w.buffer_set(channel.channel_buffer, "hidden", "1")
return w.WEECHAT_RC_OK_EAT
@@ -4756,12 +5620,12 @@ def command_hide(data, current_buffer, args):
@utf8_decode
def slack_command_cb(data, current_buffer, args):
- split_args = args.split(' ', 1)
+ split_args = args.split(" ", 1)
cmd_name = split_args[0]
- cmd_args = split_args[1] if len(split_args) > 1 else ''
- cmd = EVENTROUTER.cmds.get(cmd_name or 'help')
+ cmd_args = split_args[1] if len(split_args) > 1 else ""
+ cmd = EVENTROUTER.cmds.get(cmd_name or "help")
if not cmd:
- w.prnt('', 'Command not found: ' + cmd_name)
+ w.prnt("", "Command not found: " + cmd_name)
return w.WEECHAT_RC_OK
return cmd(data, current_buffer, cmd_args)
@@ -4777,18 +5641,24 @@ def command_help(data, current_buffer, args):
if cmd:
cmds = {args: cmd}
else:
- w.prnt('', 'Command not found: ' + args)
+ w.prnt("", "Command not found: " + args)
return w.WEECHAT_RC_OK
else:
cmds = EVENTROUTER.cmds
- w.prnt('', '\n{}'.format(colorize_string('bold', 'Slack commands:')))
+ w.prnt("", "\n{}".format(colorize_string("bold", "Slack commands:")))
- script_prefix = '{0}[{1}python{0}/{1}slack{0}]{1}'.format(w.color('green'), w.color('reset'))
+ script_prefix = "{0}[{1}python{0}/{1}slack{0}]{1}".format(
+ w.color("green"), w.color("reset")
+ )
for _, cmd in sorted(cmds.items()):
name, cmd_args, description = parse_help_docstring(cmd)
- w.prnt('', '\n{} {} {}\n\n{}'.format(
- script_prefix, colorize_string('white', name), cmd_args, description))
+ w.prnt(
+ "",
+ "\n{} {} {}\n\n{}".format(
+ script_prefix, colorize_string("white", name), cmd_args, description
+ ),
+ )
return w.WEECHAT_RC_OK
@@ -4806,7 +5676,7 @@ def command_distracting(data, current_buffer, args):
config.distracting_channels.remove(fullname)
else:
config.distracting_channels.append(fullname)
- w.config_set_plugin('distracting_channels', ','.join(config.distracting_channels))
+ w.config_set_plugin("distracting_channels", ",".join(config.distracting_channels))
return w.WEECHAT_RC_OK_EAT
@@ -4820,14 +5690,18 @@ def command_slash(data, current_buffer, args):
channel = EVENTROUTER.weechat_controller.buffers[current_buffer]
team = channel.team
- split_args = args.split(' ', 1)
+ split_args = args.split(" ", 1)
command = split_args[0]
text = split_args[1] if len(split_args) > 1 else ""
text_linkified = linkify_text(text, team, only_users=True)
- s = SlackRequest(team, "chat.command",
- {"command": command, "text": text_linkified, 'channel': channel.identifier},
- channel=channel, metadata={'command': command, 'command_args': text})
+ s = SlackRequest(
+ team,
+ "chat.command",
+ {"command": command, "text": text_linkified, "channel": channel.identifier},
+ channel=channel,
+ metadata={"command": command, "command_args": text},
+ )
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK_EAT
@@ -4844,8 +5718,12 @@ def command_mute(data, current_buffer, args):
team.muted_channels ^= {channel.identifier}
muted_str = "Muted" if channel.identifier in team.muted_channels else "Unmuted"
team.buffer_prnt("{} channel {}".format(muted_str, channel.name))
- s = SlackRequest(team, "users.prefs.set",
- {"name": "muted_channels", "value": ",".join(team.muted_channels)}, channel=channel)
+ s = SlackRequest(
+ team,
+ "users.prefs.set",
+ {"name": "muted_channels", "value": ",".join(team.muted_channels)},
+ channel=channel,
+ )
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK_EAT
@@ -4859,16 +5737,18 @@ def command_linkarchive(data, current_buffer, args):
Use cursor or mouse mode to get the id.
"""
channel = EVENTROUTER.weechat_controller.buffers[current_buffer]
- url = 'https://{}/'.format(channel.team.domain)
+ url = "https://{}/".format(channel.team.domain)
if isinstance(channel, SlackChannelCommon):
- url += 'archives/{}/'.format(channel.identifier)
+ url += "archives/{}/".format(channel.identifier)
if args:
message = channel.message_from_hash_or_index(args)
if message:
- url += 'p{}{:0>6}'.format(message.ts.majorstr(), message.ts.minorstr())
+ url += "p{}{:0>6}".format(message.ts.majorstr(), message.ts.minorstr())
if isinstance(message, SlackThreadMessage):
- url += "?thread_ts={}&cid={}".format(message.parent_message.ts, channel.identifier)
+ url += "?thread_ts={}&cid={}".format(
+ message.parent_message.ts, channel.identifier
+ )
else:
print_message_not_found_error(args)
return w.WEECHAT_RC_OK_EAT
@@ -4876,7 +5756,8 @@ def command_linkarchive(data, current_buffer, args):
w.command(current_buffer, "/input insert {}".format(url))
return w.WEECHAT_RC_OK_EAT
-command_linkarchive.completion = '%(threads) %-'
+
+command_linkarchive.completion = "%(threads) %-"
@utf8_decode
@@ -4887,8 +5768,11 @@ def command_nodistractions(data, current_buffer, args):
"""
global hide_distractions
hide_distractions = not hide_distractions
- channels = [channel for channel in EVENTROUTER.weechat_controller.buffers.values()
- if channel in config.distracting_channels]
+ channels = [
+ channel
+ for channel in EVENTROUTER.weechat_controller.buffers.values()
+ if channel in config.distracting_channels
+ ]
for channel in channels:
w.buffer_set(channel.channel_buffer, "hidden", str(int(hide_distractions)))
return w.WEECHAT_RC_OK_EAT
@@ -4905,52 +5789,60 @@ def command_upload(data, current_buffer, args):
weechat_dir = w.info_get("weechat_dir", "")
file_path = os.path.join(weechat_dir, os.path.expanduser(args))
- if channel.type == 'team':
- w.prnt('', "ERROR: Can't upload a file to the team buffer")
+ if channel.type == "team":
+ w.prnt("", "ERROR: Can't upload a file to the team buffer")
return w.WEECHAT_RC_ERROR
if not os.path.isfile(file_path):
- unescaped_file_path = file_path.replace(r'\ ', ' ')
+ unescaped_file_path = file_path.replace(r"\ ", " ")
if os.path.isfile(unescaped_file_path):
file_path = unescaped_file_path
else:
- w.prnt('', 'ERROR: Could not find file: {}'.format(file_path))
+ w.prnt("", "ERROR: Could not find file: {}".format(file_path))
return w.WEECHAT_RC_ERROR
post_data = {
- 'channels': channel.identifier,
+ "channels": channel.identifier,
}
if isinstance(channel, SlackThreadChannel):
- post_data['thread_ts'] = channel.thread_ts
+ post_data["thread_ts"] = channel.thread_ts
- url = SlackRequest(channel.team, 'files.upload', post_data, channel=channel).request_string()
- options = [
- '-s',
- '-Ffile=@{}'.format(file_path),
- url
- ]
+ url = SlackRequest(
+ channel.team, "files.upload", post_data, channel=channel
+ ).request_string()
+ options = ["-s", "-Ffile=@{}".format(file_path), url]
proxy_string = ProxyWrapper().curl()
if proxy_string:
options.append(proxy_string)
- options_hashtable = {'arg{}'.format(i + 1): arg for i, arg in enumerate(options)}
- w.hook_process_hashtable('curl', options_hashtable, config.slack_timeout, 'upload_callback', '')
+ options_hashtable = {"arg{}".format(i + 1): arg for i, arg in enumerate(options)}
+ w.hook_process_hashtable(
+ "curl", options_hashtable, config.slack_timeout, "upload_callback", ""
+ )
return w.WEECHAT_RC_OK_EAT
-command_upload.completion = '%(filename) %-'
+
+command_upload.completion = "%(filename) %-"
@utf8_decode
def upload_callback(data, command, return_code, out, err):
if return_code != 0:
- w.prnt("", "ERROR: Couldn't upload file. Got return code {}. Error: {}".format(return_code, err))
+ w.prnt(
+ "",
+ "ERROR: Couldn't upload file. Got return code {}. Error: {}".format(
+ return_code, err
+ ),
+ )
return w.WEECHAT_RC_OK_EAT
try:
response = json.loads(out)
except JSONDecodeError:
- w.prnt("", "ERROR: Couldn't process response from file upload. Got: {}".format(out))
+ w.prnt(
+ "", "ERROR: Couldn't process response from file upload. Got: {}".format(out)
+ )
return w.WEECHAT_RC_OK_EAT
if not response["ok"]:
@@ -4960,7 +5852,7 @@ def upload_callback(data, command, return_code, out, err):
@utf8_decode
def away_command_cb(data, current_buffer, args):
- all_servers, message = re.match('^/away( -all)? ?(.*)', args).groups()
+ all_servers, message = re.match("^/away( -all)? ?(.*)", args).groups()
if all_servers:
team_buffers = [team.channel_buffer for team in EVENTROUTER.teams.values()]
elif current_buffer in EVENTROUTER.weechat_controller.buffers:
@@ -5002,9 +5894,12 @@ def command_status(data, current_buffer, args):
split_args = args.split(" ", 1)
if not split_args[0]:
profile = team.users[team.myidentifier].profile
- team.buffer_prnt("Status: {} {}".format(
- replace_string_with_emoji(profile.get("status_emoji", "")),
- profile.get("status_text", "")))
+ team.buffer_prnt(
+ "Status: {} {}".format(
+ replace_string_with_emoji(profile.get("status_emoji", "")),
+ profile.get("status_text", ""),
+ )
+ )
return w.WEECHAT_RC_OK
emoji = "" if split_args[0] == "-delete" else split_args[0]
@@ -5015,14 +5910,15 @@ def command_status(data, current_buffer, args):
EVENTROUTER.receive(s)
return w.WEECHAT_RC_OK
+
command_status.completion = "-delete|%(emoji) %-"
@utf8_decode
def line_event_cb(data, signal, hashtable):
- tags = hashtable["_chat_line_tags"].split(',')
+ tags = hashtable["_chat_line_tags"].split(",")
for tag in tags:
- if tag.startswith('slack_ts_'):
+ if tag.startswith("slack_ts_"):
ts = SlackTS(tag[9:])
break
else:
@@ -5054,7 +5950,9 @@ def line_event_cb(data, signal, hashtable):
w.command(buffer_pointer, "/slack linkarchive {}".format(message_hash))
elif data == "reply":
w.command(buffer_pointer, "/cursor stop")
- w.command(buffer_pointer, "/input insert /reply {}\\x20".format(message_hash))
+ w.command(
+ buffer_pointer, "/input insert /reply {}\\x20".format(message_hash)
+ )
elif data == "thread":
w.command(buffer_pointer, "/cursor stop")
w.command(buffer_pointer, "/thread {}".format(message_hash))
@@ -5100,6 +5998,7 @@ def command_label(data, current_buffer, args):
channel.rename()
return w.WEECHAT_RC_OK
+
command_label.completion = "-unset|-full -unset %-"
@@ -5126,9 +6025,11 @@ class InvalidType(Exception):
Raised when we do type checking to ensure objects of the wrong
type are not used improperly.
"""
+
def __init__(self, type_str):
super(InvalidType, self).__init__(type_str)
+
###### New but probably old and need to migrate
@@ -5142,7 +6043,9 @@ def create_slack_debug_buffer():
global slack_debug, debug_string
if slack_debug is None:
debug_string = None
- slack_debug = w.buffer_new("slack-debug", "", "", "closed_slack_debug_buffer_cb", "")
+ slack_debug = w.buffer_new(
+ "slack-debug", "", "", "closed_slack_debug_buffer_cb", ""
+ )
w.buffer_set(slack_debug, "print_hooks_enabled", "0")
w.buffer_set(slack_debug, "notify", "0")
w.buffer_set(slack_debug, "highlight_tags_restrict", "highlight_force")
@@ -5150,24 +6053,34 @@ def create_slack_debug_buffer():
def load_emoji():
try:
- weechat_dir = w.info_get('weechat_dir', '')
- weechat_sharedir = w.info_get('weechat_sharedir', '')
- local_weemoji, global_weemoji = ('{}/weemoji.json'.format(path)
- for path in (weechat_dir, weechat_sharedir))
- path = (global_weemoji if os.path.exists(global_weemoji) and
- not os.path.exists(local_weemoji) else local_weemoji)
- with open(path, 'r') as ef:
+ weechat_dir = w.info_get("weechat_dir", "")
+ weechat_sharedir = w.info_get("weechat_sharedir", "")
+ local_weemoji, global_weemoji = (
+ "{}/weemoji.json".format(path) for path in (weechat_dir, weechat_sharedir)
+ )
+ path = (
+ global_weemoji
+ if os.path.exists(global_weemoji) and not os.path.exists(local_weemoji)
+ else local_weemoji
+ )
+ with open(path, "r") as ef:
emojis = json.loads(ef.read())
- if 'emoji' in emojis:
- print_error('The weemoji.json file is in an old format. Please update it.')
+ if "emoji" in emojis:
+ print_error(
+ "The weemoji.json file is in an old format. Please update it."
+ )
else:
- emoji_unicode = {key: value['unicode'] for key, value in emojis.items()}
+ emoji_unicode = {key: value["unicode"] for key, value in emojis.items()}
- emoji_skin_tones = {skin_tone['name']: skin_tone['unicode']
- for emoji in emojis.values()
- for skin_tone in emoji.get('skinVariations', {}).values()}
+ emoji_skin_tones = {
+ skin_tone["name"]: skin_tone["unicode"]
+ for emoji in emojis.values()
+ for skin_tone in emoji.get("skinVariations", {}).values()
+ }
- emoji_with_skin_tones = chain(emoji_unicode.items(), emoji_skin_tones.items())
+ emoji_with_skin_tones = chain(
+ emoji_unicode.items(), emoji_skin_tones.items()
+ )
emoji_with_skin_tones_reverse = {v: k for k, v in emoji_with_skin_tones}
return emoji_unicode, emoji_with_skin_tones_reverse
except:
@@ -5176,16 +6089,16 @@ def load_emoji():
def parse_help_docstring(cmd):
- doc = textwrap.dedent(cmd.__doc__).strip().split('\n', 1)
+ doc = textwrap.dedent(cmd.__doc__).strip().split("\n", 1)
cmd_line = doc[0].split(None, 1)
- args = ''.join(cmd_line[1:])
+ args = "".join(cmd_line[1:])
return cmd_line[0], args, doc[1].strip()
def setup_hooks():
- w.bar_item_new('slack_typing_notice', '(extra)typing_bar_item_cb', '')
- w.bar_item_new('away', '(extra)away_bar_item_cb', '')
- w.bar_item_new('slack_away', '(extra)away_bar_item_cb', '')
+ w.bar_item_new("slack_typing_notice", "(extra)typing_bar_item_cb", "")
+ w.bar_item_new("away", "(extra)away_bar_item_cb", "")
+ w.bar_item_new("slack_away", "(extra)away_bar_item_cb", "")
w.hook_timer(5000, 0, 0, "ws_ping_cb", "")
w.hook_timer(1000, 0, 0, "typing_update_cb", "")
@@ -5193,70 +6106,94 @@ def setup_hooks():
w.hook_timer(3000, 0, 0, "reconnect_callback", "EVENTROUTER")
w.hook_timer(1000 * 60 * 5, 0, 0, "slack_never_away_cb", "")
- w.hook_signal('buffer_closing', "buffer_closing_callback", "")
- w.hook_signal('buffer_renamed', "buffer_renamed_cb", "")
- w.hook_signal('buffer_switch', "buffer_switch_callback", "")
- w.hook_signal('window_switch', "buffer_switch_callback", "")
- w.hook_signal('quit', "quit_notification_callback", "")
+ w.hook_signal("buffer_closing", "buffer_closing_callback", "")
+ w.hook_signal("buffer_renamed", "buffer_renamed_cb", "")
+ w.hook_signal("buffer_switch", "buffer_switch_callback", "")
+ w.hook_signal("window_switch", "buffer_switch_callback", "")
+ w.hook_signal("quit", "quit_notification_callback", "")
if config.send_typing_notice:
- w.hook_signal('input_text_changed', "typing_notification_cb", "")
+ w.hook_signal("input_text_changed", "typing_notification_cb", "")
- command_help.completion = '|'.join(EVENTROUTER.cmds.keys())
- completions = '||'.join(
- '{} {}'.format(name, getattr(cmd, 'completion', ''))
- for name, cmd in EVENTROUTER.cmds.items())
+ command_help.completion = "|".join(EVENTROUTER.cmds.keys())
+ completions = "||".join(
+ "{} {}".format(name, getattr(cmd, "completion", ""))
+ for name, cmd in EVENTROUTER.cmds.items()
+ )
w.hook_command(
# Command name and description
- 'slack', 'Plugin to allow typing notification and sync of read markers for slack.com',
+ "slack",
+ "Plugin to allow typing notification and sync of read markers for slack.com",
# Usage
- '<command> [<command options>]',
+ "<command> [<command options>]",
# Description of arguments
- 'Commands:\n' +
- '\n'.join(sorted(EVENTROUTER.cmds.keys())) +
- '\nUse /slack help <command> to find out more\n',
+ "Commands:\n"
+ + "\n".join(sorted(EVENTROUTER.cmds.keys()))
+ + "\nUse /slack help <command> to find out more\n",
# Completions
completions,
# Function name
- 'slack_command_cb', '')
-
- w.hook_command_run('/me', 'me_command_cb', '')
- w.hook_command_run('/query', 'join_query_command_cb', '')
- w.hook_command_run('/join', 'join_query_command_cb', '')
- w.hook_command_run('/part', 'part_command_cb', '')
- w.hook_command_run('/topic', 'topic_command_cb', '')
- w.hook_command_run('/msg', 'msg_command_cb', '')
- w.hook_command_run('/invite', 'invite_command_cb', '')
+ "slack_command_cb",
+ "",
+ )
+
+ w.hook_command_run("/me", "me_command_cb", "")
+ w.hook_command_run("/query", "join_query_command_cb", "")
+ w.hook_command_run("/join", "join_query_command_cb", "")
+ w.hook_command_run("/part", "part_command_cb", "")
+ w.hook_command_run("/topic", "topic_command_cb", "")
+ w.hook_command_run("/msg", "msg_command_cb", "")
+ w.hook_command_run("/invite", "invite_command_cb", "")
w.hook_command_run("/input complete_next", "complete_next_cb", "")
w.hook_command_run("/input set_unread", "set_unread_cb", "")
- w.hook_command_run("/input set_unread_current_buffer", "set_unread_current_buffer_cb", "")
- w.hook_command_run('/away', 'away_command_cb', '')
- w.hook_command_run('/whois', 'whois_command_cb', '')
+ w.hook_command_run(
+ "/input set_unread_current_buffer", "set_unread_current_buffer_cb", ""
+ )
+ w.hook_command_run("/away", "away_command_cb", "")
+ w.hook_command_run("/whois", "whois_command_cb", "")
- for cmd_name in ['hide', 'label', 'rehistory', 'reply', 'thread']:
+ for cmd_name in ["hide", "label", "rehistory", "reply", "thread"]:
cmd = EVENTROUTER.cmds[cmd_name]
_, args, description = parse_help_docstring(cmd)
- completion = getattr(cmd, 'completion', '')
- w.hook_command(cmd_name, description, args, '', completion, 'command_' + cmd_name, '')
+ completion = getattr(cmd, "completion", "")
+ w.hook_command(
+ cmd_name, description, args, "", completion, "command_" + cmd_name, ""
+ )
- w.hook_completion("irc_channel_topic", "complete topic for slack", "topic_completion_cb", "")
- w.hook_completion("irc_channels", "complete channels for slack", "channel_completion_cb", "")
- w.hook_completion("irc_privates", "complete dms/mpdms for slack", "dm_completion_cb", "")
+ w.hook_completion(
+ "irc_channel_topic", "complete topic for slack", "topic_completion_cb", ""
+ )
+ w.hook_completion(
+ "irc_channels", "complete channels for slack", "channel_completion_cb", ""
+ )
+ w.hook_completion(
+ "irc_privates", "complete dms/mpdms for slack", "dm_completion_cb", ""
+ )
w.hook_completion("nicks", "complete @-nicks for slack", "nick_completion_cb", "")
- w.hook_completion("threads", "complete thread ids for slack", "thread_completion_cb", "")
- w.hook_completion("usergroups", "complete @-usergroups for slack", "usergroups_completion_cb", "")
+ w.hook_completion(
+ "threads", "complete thread ids for slack", "thread_completion_cb", ""
+ )
+ w.hook_completion(
+ "usergroups", "complete @-usergroups for slack", "usergroups_completion_cb", ""
+ )
w.hook_completion("emoji", "complete :emoji: for slack", "emoji_completion_cb", "")
- w.key_bind("mouse", {
- "@chat(python.*):button2": "hsignal:slack_mouse",
- })
- w.key_bind("cursor", {
- "@chat(python.*):D": "hsignal:slack_cursor_delete",
- "@chat(python.*):L": "hsignal:slack_cursor_linkarchive",
- "@chat(python.*):M": "hsignal:slack_cursor_message",
- "@chat(python.*):R": "hsignal:slack_cursor_reply",
- "@chat(python.*):T": "hsignal:slack_cursor_thread",
- })
+ w.key_bind(
+ "mouse",
+ {
+ "@chat(python.*):button2": "hsignal:slack_mouse",
+ },
+ )
+ w.key_bind(
+ "cursor",
+ {
+ "@chat(python.*):D": "hsignal:slack_cursor_delete",
+ "@chat(python.*):L": "hsignal:slack_cursor_linkarchive",
+ "@chat(python.*):M": "hsignal:slack_cursor_message",
+ "@chat(python.*):R": "hsignal:slack_cursor_reply",
+ "@chat(python.*):T": "hsignal:slack_cursor_thread",
+ },
+ )
w.hook_hsignal("slack_mouse", "line_event_cb", "auto")
w.hook_hsignal("slack_cursor_delete", "line_event_cb", "delete")
@@ -5270,6 +6207,7 @@ def setup_hooks():
# w.hook_signal('window_scrolled', "scrolled_cb", "")
# w.hook_timer(3000, 0, 0, "slack_connection_persistence_cb", "")
+
##### END NEW
@@ -5282,10 +6220,10 @@ def dbg(message, level=0, main_buffer=False, fout=False):
global debug_string
message = "DEBUG: {}".format(message)
if fout:
- with open('/tmp/debug.log', 'a+') as log_file:
- log_file.writelines(message + '\n')
+ with open("/tmp/debug.log", "a+") as log_file:
+ log_file.writelines(message + "\n")
if main_buffer:
- w.prnt("", "slack: " + message)
+ w.prnt("", "slack: " + message)
else:
if slack_debug and (not debug_string or debug_string in message):
w.prnt(slack_debug, message)
@@ -5293,7 +6231,7 @@ def dbg(message, level=0, main_buffer=False, fout=False):
###### Config code
class PluginConfig(object):
- Setting = collections.namedtuple('Setting', ['default', 'desc'])
+ Setting = collections.namedtuple("Setting", ["default", "desc"])
# Default settings.
# These are, initially, each a (default, desc) tuple; the former is the
# default value of the setting, in the (string) format that weechat
@@ -5304,185 +6242,216 @@ class PluginConfig(object):
# Following this procedure, the keys remain the same, but the values are
# the real (python) values of the settings.
default_settings = {
- 'auto_open_threads': Setting(
- default='false',
- desc='Automatically open threads when mentioned or in'
- 'response to own messages.'),
- 'background_load_all_history': Setting(
- default='true',
- desc='Load the history for all channels in the background when the script is loaded,'
- ' rather than waiting until the buffer is switched to. You can set this to false if'
- ' you experience performance issues, however that causes some loss of functionality,'
- ' see known issues in the readme.'),
- 'channel_name_typing_indicator': Setting(
- default='true',
- desc='Change the prefix of a channel from # to > when someone is'
- ' typing in it. Note that this will (temporarily) affect the sort'
- ' order if you sort buffers by name rather than by number.'),
- 'color_buflist_muted_channels': Setting(
- default='darkgray',
- desc='Color to use for muted channels in the buflist'),
- 'color_deleted': Setting(
- default='red',
- desc='Color to use for deleted messages and files.'),
- 'color_edited_suffix': Setting(
- default='095',
- desc='Color to use for (edited) suffix on messages that have been edited.'),
- 'color_reaction_suffix': Setting(
- default='darkgray',
- desc='Color to use for the [:wave:(@user)] suffix on messages that'
- ' have reactions attached to them.'),
- 'color_reaction_suffix_added_by_you': Setting(
- default='blue',
- desc='Color to use for reactions that you have added.'),
- 'color_thread_suffix': Setting(
- default='lightcyan',
- desc='Color to use for the [thread: XXX] suffix on messages that'
+ "auto_open_threads": Setting(
+ default="false",
+ desc="Automatically open threads when mentioned or in"
+ "response to own messages.",
+ ),
+ "background_load_all_history": Setting(
+ default="true",
+ desc="Load the history for all channels in the background when the script is loaded,"
+ " rather than waiting until the buffer is switched to. You can set this to false if"
+ " you experience performance issues, however that causes some loss of functionality,"
+ " see known issues in the readme.",
+ ),
+ "channel_name_typing_indicator": Setting(
+ default="true",
+ desc="Change the prefix of a channel from # to > when someone is"
+ " typing in it. Note that this will (temporarily) affect the sort"
+ " order if you sort buffers by name rather than by number.",
+ ),
+ "color_buflist_muted_channels": Setting(
+ default="darkgray", desc="Color to use for muted channels in the buflist"
+ ),
+ "color_deleted": Setting(
+ default="red", desc="Color to use for deleted messages and files."
+ ),
+ "color_edited_suffix": Setting(
+ default="095",
+ desc="Color to use for (edited) suffix on messages that have been edited.",
+ ),
+ "color_reaction_suffix": Setting(
+ default="darkgray",
+ desc="Color to use for the [:wave:(@user)] suffix on messages that"
+ " have reactions attached to them.",
+ ),
+ "color_reaction_suffix_added_by_you": Setting(
+ default="blue", desc="Color to use for reactions that you have added."
+ ),
+ "color_thread_suffix": Setting(
+ default="lightcyan",
+ desc="Color to use for the [thread: XXX] suffix on messages that"
' have threads attached to them. The special value "multiple" can'
- ' be used to use a different color for each thread.'),
- 'color_typing_notice': Setting(
- default='yellow',
- desc='Color to use for the typing notice.'),
- 'colorize_attachments': Setting(
- default='prefix',
+ " be used to use a different color for each thread.",
+ ),
+ "color_typing_notice": Setting(
+ default="yellow", desc="Color to use for the typing notice."
+ ),
+ "colorize_attachments": Setting(
+ default="prefix",
desc='Whether to colorize attachment lines. Values: "prefix": Only colorize'
- ' the prefix, "all": Colorize the whole line, "none": Don\'t colorize.'),
- 'colorize_private_chats': Setting(
- default='false',
- desc='Whether to use nick-colors in DM windows.'),
- 'debug_mode': Setting(
- default='false',
- desc='Open a dedicated buffer for debug messages and start logging'
- ' to it. How verbose the logging is depends on log_level.'),
- 'debug_level': Setting(
- default='3',
- desc='Show only this level of debug info (or higher) when'
- ' debug_mode is on. Lower levels -> more messages.'),
- 'distracting_channels': Setting(
- default='',
- desc='List of channels to hide.'),
- 'external_user_suffix': Setting(
- default='*',
- desc='The suffix appended to nicks to indicate external users.'),
- 'files_download_location': Setting(
- default='',
- desc='If set, file attachments will be automatically downloaded'
+ ' the prefix, "all": Colorize the whole line, "none": Don\'t colorize.',
+ ),
+ "colorize_private_chats": Setting(
+ default="false", desc="Whether to use nick-colors in DM windows."
+ ),
+ "debug_mode": Setting(
+ default="false",
+ desc="Open a dedicated buffer for debug messages and start logging"
+ " to it. How verbose the logging is depends on log_level.",
+ ),
+ "debug_level": Setting(
+ default="3",
+ desc="Show only this level of debug info (or higher) when"
+ " debug_mode is on. Lower levels -> more messages.",
+ ),
+ "distracting_channels": Setting(default="", desc="List of channels to hide."),
+ "external_user_suffix": Setting(
+ default="*", desc="The suffix appended to nicks to indicate external users."
+ ),
+ "files_download_location": Setting(
+ default="",
+ desc="If set, file attachments will be automatically downloaded"
' to this location. "%h" will be replaced by WeeChat home,'
- ' "~/.weechat" by default. Requires WeeChat 2.2 or newer.'),
- 'group_name_prefix': Setting(
- default='&',
- desc='The prefix of buffer names for groups (private channels).'),
- 'history_fetch_count': Setting(
- default='200',
- desc='The number of messages to fetch for each channel when fetching'
- ' history, between 1 and 1000.'),
- 'link_previews': Setting(
- default='true',
- desc='Show previews of website content linked by teammates.'),
- 'map_underline_to': Setting(
- default='_',
- desc='When sending underlined text to slack, use this formatting'
+ ' "~/.weechat" by default. Requires WeeChat 2.2 or newer.',
+ ),
+ "group_name_prefix": Setting(
+ default="&",
+ desc="The prefix of buffer names for groups (private channels).",
+ ),
+ "history_fetch_count": Setting(
+ default="200",
+ desc="The number of messages to fetch for each channel when fetching"
+ " history, between 1 and 1000.",
+ ),
+ "link_previews": Setting(
+ default="true", desc="Show previews of website content linked by teammates."
+ ),
+ "map_underline_to": Setting(
+ default="_",
+ desc="When sending underlined text to slack, use this formatting"
' character for it. The default ("_") sends it as italics. Use'
- ' "*" to send bold instead.'),
- 'muted_channels_activity': Setting(
- default='personal_highlights',
+ ' "*" to send bold instead.',
+ ),
+ "muted_channels_activity": Setting(
+ default="personal_highlights",
desc="Control which activity you see from muted channels, either"
" none, personal_highlights, all_highlights or all. none: Don't"
" show any activity. personal_highlights: Only show personal"
" highlights, i.e. not @channel and @here. all_highlights: Show"
" all highlights, but not other messages. all: Show all activity,"
- " like other channels."),
- 'notify_subscribed_threads': Setting(
- default='auto',
+ " like other channels.",
+ ),
+ "notify_subscribed_threads": Setting(
+ default="auto",
desc="Control if you want to see a notification in the team buffer when a"
" thread you're subscribed to receives a new message, either auto, true or"
" false. auto means that you only get a notification if auto_open_threads"
- " and thread_messages_in_channel both are false. Defaults to auto."),
- 'notify_usergroup_handle_updated': Setting(
- default='false',
+ " and thread_messages_in_channel both are false. Defaults to auto.",
+ ),
+ "notify_usergroup_handle_updated": Setting(
+ default="false",
desc="Control if you want to see a notification in the team buffer when a"
- "usergroup's handle has changed, either true or false."),
- 'never_away': Setting(
- default='false',
- desc='Poke Slack every five minutes so that it never marks you "away".'),
- 'record_events': Setting(
- default='false',
- desc='Log all traffic from Slack to disk as JSON.'),
- 'render_bold_as': Setting(
- default='bold',
- desc='When receiving bold text from Slack, render it as this in weechat.'),
- 'render_emoji_as_string': Setting(
- default='false',
+ "usergroup's handle has changed, either true or false.",
+ ),
+ "never_away": Setting(
+ default="false",
+ desc='Poke Slack every five minutes so that it never marks you "away".',
+ ),
+ "record_events": Setting(
+ default="false", desc="Log all traffic from Slack to disk as JSON."
+ ),
+ "render_bold_as": Setting(
+ default="bold",
+ desc="When receiving bold text from Slack, render it as this in weechat.",
+ ),
+ "render_emoji_as_string": Setting(
+ default="false",
desc="Render emojis as :emoji_name: instead of emoji characters. Enable this"
" if your terminal doesn't support emojis, or set to 'both' if you want to"
" see both renderings. Note that even though this is"
" disabled by default, you need to place {}/blob/master/weemoji.json in your"
- " weechat directory to enable rendering emojis as emoji characters."
- .format(REPO_URL)),
- 'render_italic_as': Setting(
- default='italic',
- desc='When receiving bold text from Slack, render it as this in weechat.'
- ' If your terminal lacks italic support, consider using "underline" instead.'),
- 'send_typing_notice': Setting(
- default='true',
- desc='Alert Slack users when you are typing a message in the input bar '
- '(Requires reload)'),
- 'server_aliases': Setting(
- default='',
- desc='A comma separated list of `subdomain:alias` pairs. The alias'
- ' will be used instead of the actual name of the slack (in buffer'
- ' names, logging, etc). E.g `work:no_fun_allowed` would make your'
- ' work slack show up as `no_fun_allowed` rather than `work.slack.com`.'),
- 'shared_name_prefix': Setting(
- default='%',
- desc='The prefix of buffer names for shared channels.'),
- 'short_buffer_names': Setting(
- default='false',
- desc='Use `foo.#channel` rather than `foo.slack.com.#channel` as the'
- ' internal name for Slack buffers.'),
- 'show_buflist_presence': Setting(
- default='true',
- desc='Display a `+` character in the buffer list for present users.'),
- 'show_reaction_nicks': Setting(
- default='false',
- desc='Display the name of the reacting user(s) alongside each reactji.'),
- 'slack_api_token': Setting(
- default='INSERT VALID KEY HERE!',
- desc='List of Slack API tokens, one per Slack instance you want to'
- ' connect to. See the README for details on how to get these.'),
- 'slack_timeout': Setting(
- default='20000',
- desc='How long (ms) to wait when communicating with Slack.'),
- 'switch_buffer_on_join': Setting(
- default='true',
- desc='When /joining a channel, automatically switch to it as well.'),
- 'thread_messages_in_channel': Setting(
- default='false',
- desc='When enabled shows thread messages in the parent channel.'),
- 'unfurl_ignore_alt_text': Setting(
- default='false',
+ " weechat directory to enable rendering emojis as emoji characters.".format(
+ REPO_URL
+ ),
+ ),
+ "render_italic_as": Setting(
+ default="italic",
+ desc="When receiving bold text from Slack, render it as this in weechat."
+ ' If your terminal lacks italic support, consider using "underline" instead.',
+ ),
+ "send_typing_notice": Setting(
+ default="true",
+ desc="Alert Slack users when you are typing a message in the input bar "
+ "(Requires reload)",
+ ),
+ "server_aliases": Setting(
+ default="",
+ desc="A comma separated list of `subdomain:alias` pairs. The alias"
+ " will be used instead of the actual name of the slack (in buffer"
+ " names, logging, etc). E.g `work:no_fun_allowed` would make your"
+ " work slack show up as `no_fun_allowed` rather than `work.slack.com`.",
+ ),
+ "shared_name_prefix": Setting(
+ default="%", desc="The prefix of buffer names for shared channels."
+ ),
+ "short_buffer_names": Setting(
+ default="false",
+ desc="Use `foo.#channel` rather than `foo.slack.com.#channel` as the"
+ " internal name for Slack buffers.",
+ ),
+ "show_buflist_presence": Setting(
+ default="true",
+ desc="Display a `+` character in the buffer list for present users.",
+ ),
+ "show_reaction_nicks": Setting(
+ default="false",
+ desc="Display the name of the reacting user(s) alongside each reactji.",
+ ),
+ "slack_api_token": Setting(
+ default="INSERT VALID KEY HERE!",
+ desc="List of Slack API tokens, one per Slack instance you want to"
+ " connect to. See the README for details on how to get these.",
+ ),
+ "slack_timeout": Setting(
+ default="20000", desc="How long (ms) to wait when communicating with Slack."
+ ),
+ "switch_buffer_on_join": Setting(
+ default="true",
+ desc="When /joining a channel, automatically switch to it as well.",
+ ),
+ "thread_messages_in_channel": Setting(
+ default="false",
+ desc="When enabled shows thread messages in the parent channel.",
+ ),
+ "unfurl_ignore_alt_text": Setting(
+ default="false",
desc='When displaying ("unfurling") links to channels/users/etc,'
' ignore the "alt text" present in the message and instead use the'
- ' canonical name of the thing being linked to.'),
- 'unfurl_auto_link_display': Setting(
- default='both',
+ " canonical name of the thing being linked to.",
+ ),
+ "unfurl_auto_link_display": Setting(
+ default="both",
desc='When displaying ("unfurling") links to channels/users/etc,'
- ' determine what is displayed when the text matches the url'
- ' without the protocol. This happens when Slack automatically'
- ' creates links, e.g. from words separated by dots or email'
+ " determine what is displayed when the text matches the url"
+ " without the protocol. This happens when Slack automatically"
+ " creates links, e.g. from words separated by dots or email"
' addresses. Set it to "text" to only display the text written by'
' the user, "url" to only display the url or "both" (the default)'
- ' to display both.'),
- 'unhide_buffers_with_activity': Setting(
- default='false',
- desc='When activity occurs on a buffer, unhide it even if it was'
- ' previously hidden (whether by the user or by the'
- ' distracting_channels setting).'),
- 'use_full_names': Setting(
- default='false',
- desc='Use full names as the nicks for all users. When this is'
- ' false (the default), display names will be used if set, with a'
- ' fallback to the full name if display name is not set.'),
+ " to display both.",
+ ),
+ "unhide_buffers_with_activity": Setting(
+ default="false",
+ desc="When activity occurs on a buffer, unhide it even if it was"
+ " previously hidden (whether by the user or by the"
+ " distracting_channels setting).",
+ ),
+ "use_full_names": Setting(
+ default="false",
+ desc="Use full names as the nicks for all users. When this is"
+ " false (the default), display names will be used if set, with a"
+ " fallback to the full name if display name is not set.",
+ ),
}
# Set missing settings to their defaults. Load non-missing settings from
@@ -5504,7 +6473,9 @@ class PluginConfig(object):
self.config_changed(None, None, None)
def __str__(self):
- return "".join([x + "\t" + str(self.settings[x]) + "\n" for x in self.settings.keys()])
+ return "".join(
+ [x + "\t" + str(self.settings[x]) + "\n" for x in self.settings.keys()]
+ )
def config_changed(self, data, full_key, value):
if full_key is None:
@@ -5514,13 +6485,15 @@ class PluginConfig(object):
key = full_key.replace(CONFIG_PREFIX + ".", "")
self.settings[key] = self.fetch_setting(key)
- if (full_key is None or full_key == CONFIG_PREFIX + ".debug_mode") and self.debug_mode:
+ if (
+ full_key is None or full_key == CONFIG_PREFIX + ".debug_mode"
+ ) and self.debug_mode:
create_slack_debug_buffer()
return w.WEECHAT_RC_OK
def fetch_setting(self, key):
try:
- return getattr(self, 'get_' + key)(key)
+ return getattr(self, "get_" + key)(key)
except AttributeError:
# Most settings are on/off, so make get_boolean the default
return self.get_boolean(key)
@@ -5570,15 +6543,15 @@ class PluginConfig(object):
get_unfurl_auto_link_display = get_string
def get_distracting_channels(self, key):
- return [x.strip() for x in w.config_get_plugin(key).split(',') if x]
+ return [x.strip() for x in w.config_get_plugin(key).split(",") if x]
def get_server_aliases(self, key):
alias_list = w.config_get_plugin(key)
- return dict(item.split(":") for item in alias_list.split(",") if ':' in item)
+ return dict(item.split(":") for item in alias_list.split(",") if ":" in item)
def get_slack_api_token(self, key):
token = w.config_get_plugin("slack_api_token")
- if token.startswith('${sec.data'):
+ if token.startswith("${sec.data"):
return w.string_eval_expression(token, {}, {}, {})
else:
return token
@@ -5590,10 +6563,10 @@ class PluginConfig(object):
return w.config_string_to_boolean(value)
def get_notify_subscribed_threads(self, key):
- return self.get_string_or_boolean(key, 'auto')
+ return self.get_string_or_boolean(key, "auto")
def get_render_emoji_as_string(self, key):
- return self.get_string_or_boolean(key, 'both')
+ return self.get_string_or_boolean(key, "both")
def migrate(self):
"""
@@ -5625,16 +6598,16 @@ def config_server_buffer_cb(data, key, value):
def setup_trace():
global f
now = time.time()
- f = open('{}/{}-trace.json'.format(RECORD_DIR, now), 'w')
+ f = open("{}/{}-trace.json".format(RECORD_DIR, now), "w")
def trace_calls(frame, event, arg):
global f
- if event != 'call':
+ if event != "call":
return
co = frame.f_code
func_name = co.co_name
- if func_name == 'write':
+ if func_name == "write":
# Ignore write() calls from print statements
return
func_line_no = frame.f_lineno
@@ -5642,38 +6615,57 @@ def trace_calls(frame, event, arg):
caller = frame.f_back
caller_line_no = caller.f_lineno
caller_filename = caller.f_code.co_filename
- print('Call to %s on line %s of %s from line %s of %s' % \
- (func_name, func_line_no, func_filename,
- caller_line_no, caller_filename), file=f)
+ print(
+ "Call to %s on line %s of %s from line %s of %s"
+ % (func_name, func_line_no, func_filename, caller_line_no, caller_filename),
+ file=f,
+ )
f.flush()
return
def initiate_connection(token, retries=3, team=None, reconnect=False):
- return SlackRequest(team,
- 'rtm.{}'.format('connect' if team else 'start'),
- {"batch_presence_aware": 1},
- retries=retries,
- token=token,
- metadata={'reconnect': reconnect})
+ return SlackRequest(
+ team,
+ "rtm.{}".format("connect" if team else "start"),
+ {"batch_presence_aware": 1},
+ retries=retries,
+ token=token,
+ metadata={"reconnect": reconnect},
+ )
if __name__ == "__main__":
w = WeechatWrapper(weechat)
- if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
- SCRIPT_DESC, "script_unloaded", ""):
+ if w.register(
+ SCRIPT_NAME,
+ SCRIPT_AUTHOR,
+ SCRIPT_VERSION,
+ SCRIPT_LICENSE,
+ SCRIPT_DESC,
+ "script_unloaded",
+ "",
+ ):
weechat_version = int(w.info_get("version_number", "") or 0)
weechat_upgrading = w.info_get("weechat_upgrading", "")
if weechat_version < 0x1030000:
- w.prnt("", "\nERROR: Weechat version 1.3+ is required to use {}.\n\n".format(SCRIPT_NAME))
+ w.prnt(
+ "",
+ "\nERROR: Weechat version 1.3+ is required to use {}.\n\n".format(
+ SCRIPT_NAME
+ ),
+ )
elif weechat_upgrading == "1":
- w.prnt("", "NOTE: wee-slack will not work after running /upgrade until it's"
+ w.prnt(
+ "",
+ "NOTE: wee-slack will not work after running /upgrade until it's"
" reloaded. Please run `/python reload slack` to continue using it. You"
- " will not receive any new messages in wee-slack buffers until doing this.")
+ " will not receive any new messages in wee-slack buffers until doing this.",
+ )
else:
global EVENTROUTER
@@ -5707,9 +6699,13 @@ if __name__ == "__main__":
auto_connect = weechat.info_get("auto_connect", "") != "0"
if auto_connect:
- tokens = [token.strip() for token in config.slack_api_token.split(',')]
- w.prnt('', 'Connecting to {} slack team{}.'
- .format(len(tokens), '' if len(tokens) == 1 else 's'))
+ tokens = [token.strip() for token in config.slack_api_token.split(",")]
+ w.prnt(
+ "",
+ "Connecting to {} slack team{}.".format(
+ len(tokens), "" if len(tokens) == 1 else "s"
+ ),
+ )
for t in tokens:
s = initiate_connection(t)
EVENTROUTER.receive(s)