csp-adapter-slack 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/.gitignore +4 -0
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/PKG-INFO +13 -7
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/README.md +7 -1
- csp_adapter_slack-0.3.0/csp_adapter_slack/__init__.py +6 -0
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/csp_adapter_slack/adapter.py +70 -45
- csp_adapter_slack-0.3.0/csp_adapter_slack/examples/__init__.py +0 -0
- csp_adapter_slack-0.3.0/csp_adapter_slack/examples/hello.py +44 -0
- csp_adapter_slack-0.3.0/csp_adapter_slack/mention.py +10 -0
- csp_adapter_slack-0.3.0/csp_adapter_slack/message.py +40 -0
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/csp_adapter_slack/tests/test_adapter.py +6 -6
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/pyproject.toml +7 -8
- csp_adapter_slack-0.2.0/csp_adapter_slack/__init__.py +0 -4
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/LICENSE +0 -0
- {csp_adapter_slack-0.2.0 → csp_adapter_slack-0.3.0}/csp_adapter_slack/adapter_config.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: csp_adapter_slack
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
4
4
|
Summary: A csp adapter for slack
|
5
5
|
Project-URL: Repository, https://github.com/point72/csp-adapter-slack
|
6
6
|
Project-URL: Homepage, https://github.com/point72/csp-adapter-slack
|
@@ -206,32 +206,32 @@ License: Apache License
|
|
206
206
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
207
207
|
See the License for the specific language governing permissions and
|
208
208
|
limitations under the License.
|
209
|
+
License-File: LICENSE
|
209
210
|
Keywords: chat,chatbot,csp,slack,stream-processing
|
210
211
|
Classifier: Development Status :: 4 - Beta
|
211
212
|
Classifier: Framework :: Jupyter
|
212
213
|
Classifier: License :: OSI Approved :: Apache Software License
|
213
214
|
Classifier: Programming Language :: Python
|
214
215
|
Classifier: Programming Language :: Python :: 3
|
215
|
-
Classifier: Programming Language :: Python :: 3.8
|
216
216
|
Classifier: Programming Language :: Python :: 3.9
|
217
217
|
Classifier: Programming Language :: Python :: 3.10
|
218
218
|
Classifier: Programming Language :: Python :: 3.11
|
219
219
|
Classifier: Programming Language :: Python :: 3.12
|
220
220
|
Classifier: Programming Language :: Python :: 3.13
|
221
|
-
Requires-Python: >=3.
|
221
|
+
Requires-Python: >=3.9
|
222
222
|
Requires-Dist: csp
|
223
223
|
Requires-Dist: pydantic>=2
|
224
224
|
Requires-Dist: slack-sdk>=3
|
225
225
|
Provides-Extra: develop
|
226
226
|
Requires-Dist: bump-my-version; extra == 'develop'
|
227
227
|
Requires-Dist: check-manifest; extra == 'develop'
|
228
|
-
Requires-Dist: codespell<2.
|
228
|
+
Requires-Dist: codespell<2.5,>=2.2.6; extra == 'develop'
|
229
229
|
Requires-Dist: hatchling; extra == 'develop'
|
230
230
|
Requires-Dist: mdformat-tables<1.1,>=1; extra == 'develop'
|
231
231
|
Requires-Dist: mdformat<0.8,>=0.7.17; extra == 'develop'
|
232
232
|
Requires-Dist: pytest; extra == 'develop'
|
233
233
|
Requires-Dist: pytest-cov; extra == 'develop'
|
234
|
-
Requires-Dist: ruff<0.
|
234
|
+
Requires-Dist: ruff<0.12,>=0.5; extra == 'develop'
|
235
235
|
Requires-Dist: twine<7,>=5; extra == 'develop'
|
236
236
|
Provides-Extra: test
|
237
237
|
Requires-Dist: pytest; extra == 'test'
|
@@ -249,8 +249,14 @@ A [csp](https://github.com/point72/csp) adapter for [slack](https://slack.com)
|
|
249
249
|
|
250
250
|
## Features
|
251
251
|
|
252
|
+
The Slack adapter allows for reading and writing of messages from the [Slack](https://slack.com/) message platform using the [`slack-sdk`](https://tools.slack.dev/python-slack-sdk/).
|
253
|
+
|
252
254
|
[More information is available in our wiki](https://github.com/Point72/csp-adapter-slack/wiki)
|
253
255
|
|
256
|
+
## Chat Framework
|
257
|
+
|
258
|
+
[`csp-bot`](https://github.com/Point72/csp-bot) is a framework for writing cross-platform, command oriented chat bots.
|
259
|
+
|
254
260
|
## Installation
|
255
261
|
|
256
262
|
Install with `pip`:
|
@@ -267,4 +273,4 @@ conda install csp csp-adapter-slack -c conda-forge
|
|
267
273
|
|
268
274
|
## License
|
269
275
|
|
270
|
-
This software is licensed under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
|
276
|
+
This software is licensed under the Apache 2.0 license. See the [LICENSE](https://github.com/Point72/csp-adapter-slack/blob/main/LICENSE) file for details.
|
@@ -9,8 +9,14 @@ A [csp](https://github.com/point72/csp) adapter for [slack](https://slack.com)
|
|
9
9
|
|
10
10
|
## Features
|
11
11
|
|
12
|
+
The Slack adapter allows for reading and writing of messages from the [Slack](https://slack.com/) message platform using the [`slack-sdk`](https://tools.slack.dev/python-slack-sdk/).
|
13
|
+
|
12
14
|
[More information is available in our wiki](https://github.com/Point72/csp-adapter-slack/wiki)
|
13
15
|
|
16
|
+
## Chat Framework
|
17
|
+
|
18
|
+
[`csp-bot`](https://github.com/Point72/csp-bot) is a framework for writing cross-platform, command oriented chat bots.
|
19
|
+
|
14
20
|
## Installation
|
15
21
|
|
16
22
|
Install with `pip`:
|
@@ -27,4 +33,4 @@ conda install csp csp-adapter-slack -c conda-forge
|
|
27
33
|
|
28
34
|
## License
|
29
35
|
|
30
|
-
This software is licensed under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
|
36
|
+
This software is licensed under the Apache 2.0 license. See the [LICENSE](https://github.com/Point72/csp-adapter-slack/blob/main/LICENSE) file for details.
|
@@ -9,7 +9,6 @@ import csp
|
|
9
9
|
from csp.impl.adaptermanager import AdapterManagerImpl
|
10
10
|
from csp.impl.outputadapter import OutputAdapter
|
11
11
|
from csp.impl.pushadapter import PushInputAdapter
|
12
|
-
from csp.impl.struct import Struct
|
13
12
|
from csp.impl.types.tstype import ts
|
14
13
|
from csp.impl.wiring import py_output_adapter_def, py_push_adapter_def
|
15
14
|
from slack_sdk.errors import SlackApiError
|
@@ -19,33 +18,13 @@ from slack_sdk.socket_mode.response import SocketModeResponse
|
|
19
18
|
from slack_sdk.web import WebClient
|
20
19
|
|
21
20
|
from .adapter_config import SlackAdapterConfig
|
21
|
+
from .message import SlackMessage
|
22
22
|
|
23
23
|
T = TypeVar("T")
|
24
24
|
log = getLogger(__file__)
|
25
25
|
|
26
26
|
|
27
|
-
__all__ = ("
|
28
|
-
|
29
|
-
|
30
|
-
class SlackMessage(Struct):
|
31
|
-
user: str
|
32
|
-
user_email: str # email of the author
|
33
|
-
user_id: str # user id of the author
|
34
|
-
tags: List[str] # list of mentions
|
35
|
-
|
36
|
-
channel: str # name of channel
|
37
|
-
channel_id: str # id of channel
|
38
|
-
channel_type: str # type of channel, in "message", "public" (app_mention), "private" (app_mention)
|
39
|
-
|
40
|
-
msg: str # parsed text payload
|
41
|
-
reaction: str # emoji reacts
|
42
|
-
thread: str # thread id, if in thread
|
43
|
-
payload: dict # raw message payload
|
44
|
-
|
45
|
-
|
46
|
-
def mention_user(userid: str) -> str:
|
47
|
-
"""Convenience method, more difficult to do in symphony but we want slack to be symmetric"""
|
48
|
-
return f"<@{userid}>"
|
27
|
+
__all__ = ("SlackAdapterManager", "SlackInputAdapterImpl", "SlackOutputAdapterImpl")
|
49
28
|
|
50
29
|
|
51
30
|
class SlackAdapterManager(AdapterManagerImpl):
|
@@ -69,14 +48,18 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
69
48
|
self._thread: Thread = None
|
70
49
|
|
71
50
|
# lookups for mentions and redirection
|
72
|
-
self.
|
73
|
-
self.
|
74
|
-
self.
|
51
|
+
self._channel_id_to_channel_name: Dict[str, str] = {}
|
52
|
+
self._channel_id_to_channel_type: Dict[str, str] = {}
|
53
|
+
self._channel_name_to_channel_id: Dict[str, str] = {}
|
75
54
|
self._user_id_to_user_name: Dict[str, str] = {}
|
76
55
|
self._user_id_to_user_email: Dict[str, str] = {}
|
77
56
|
self._user_name_to_user_id: Dict[str, str] = {}
|
78
57
|
self._user_email_to_user_id: Dict[str, str] = {}
|
79
58
|
|
59
|
+
# if subscribed to mentions AND events, will get 2 copies,
|
60
|
+
# so we want to dedupe by id
|
61
|
+
self._seen_msg_ids = set()
|
62
|
+
|
80
63
|
def subscribe(self):
|
81
64
|
return _slack_input_adapter(self, push_mode=csp.PushMode.NON_COLLAPSING)
|
82
65
|
|
@@ -137,14 +120,33 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
137
120
|
if ret.status_code == 200:
|
138
121
|
# TODO OAuth scopes required
|
139
122
|
for user in ret.data["members"]:
|
123
|
+
# Grab name
|
140
124
|
name = user["profile"].get("real_name_normalized", user["name"])
|
141
|
-
|
142
|
-
|
125
|
+
|
126
|
+
# Try to grab id
|
127
|
+
if "id" in user:
|
128
|
+
user_id = user["id"]
|
129
|
+
elif "id" in user["profile"]:
|
130
|
+
user_id = user["profile"]["id"]
|
131
|
+
else:
|
132
|
+
raise RuntimeError(f"No id found in user profile: {user}")
|
133
|
+
|
134
|
+
# Try to grab email
|
135
|
+
if "email" in user["profile"]:
|
136
|
+
email = user["profile"]["email"]
|
137
|
+
else:
|
138
|
+
log.warning(f"No email found in user profile, using id: {user}")
|
139
|
+
email = user_id
|
140
|
+
|
143
141
|
self._user_id_to_user_name[user_id] = name
|
144
142
|
self._user_name_to_user_id[name] = user_id # TODO is this 1-1 in slack?
|
145
143
|
self._user_id_to_user_email[user_id] = email
|
146
144
|
self._user_email_to_user_id[email] = user_id
|
147
|
-
|
145
|
+
|
146
|
+
user_id = self._user_name_to_user_id.get(user_name, None)
|
147
|
+
if user_id is None:
|
148
|
+
# no user found
|
149
|
+
raise ValueError(f"User {user_name} not found in Slack")
|
148
150
|
return user_id
|
149
151
|
|
150
152
|
def _channel_data_to_channel_kind(self, data) -> str:
|
@@ -156,8 +158,8 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
156
158
|
|
157
159
|
def _get_channel_from_id(self, channel_id):
|
158
160
|
# try to pull from cache
|
159
|
-
name = self.
|
160
|
-
kind = self.
|
161
|
+
name = self._channel_id_to_channel_name.get(channel_id, None)
|
162
|
+
kind = self._channel_id_to_channel_type.get(channel_id, None)
|
161
163
|
|
162
164
|
# if none, refresh data via web client
|
163
165
|
if name is None:
|
@@ -167,18 +169,29 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
167
169
|
kind = self._channel_data_to_channel_kind(ret.data["channel"])
|
168
170
|
if kind == "message":
|
169
171
|
# TODO use same behavior as symphony adapter
|
170
|
-
name = "
|
172
|
+
name = "IM"
|
171
173
|
else:
|
172
174
|
name = ret.data["channel"]["name"]
|
173
175
|
|
174
|
-
|
175
|
-
|
176
|
-
|
176
|
+
if name == "IM":
|
177
|
+
# store by the name of the user
|
178
|
+
user = ret.data["channel"]["user"]
|
179
|
+
user_name = self._get_user_from_id(user)[0]
|
180
|
+
self._channel_name_to_channel_id[user_name] = channel_id
|
181
|
+
else:
|
182
|
+
self._channel_name_to_channel_id[name] = channel_id
|
183
|
+
self._channel_id_to_channel_name[channel_id] = name
|
184
|
+
self._channel_id_to_channel_type[channel_id] = kind
|
177
185
|
return name, kind
|
178
186
|
|
179
187
|
def _get_channel_from_name(self, channel_name):
|
180
|
-
#
|
181
|
-
|
188
|
+
# first, see if its a regular name or tagged name
|
189
|
+
if channel_name.startswith("<#") and channel_name.endswith("|>"):
|
190
|
+
# strip out the tag
|
191
|
+
channel_id = channel_name[2:-2]
|
192
|
+
else:
|
193
|
+
# try to pull from cache
|
194
|
+
channel_id = self._channel_name_to_channel_id.get(channel_name, None)
|
182
195
|
|
183
196
|
# if none, refresh data via web client
|
184
197
|
if channel_id is None:
|
@@ -191,10 +204,13 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
191
204
|
name = channel["name"]
|
192
205
|
channel_id = channel["id"]
|
193
206
|
kind = self._channel_data_to_channel_kind(channel)
|
194
|
-
self.
|
195
|
-
self.
|
196
|
-
self.
|
197
|
-
|
207
|
+
self._channel_id_to_channel_name[channel_id] = name
|
208
|
+
self._channel_name_to_channel_id[name] = channel_id
|
209
|
+
self._channel_id_to_channel_type[channel_id] = kind
|
210
|
+
channel_id = self._channel_name_to_channel_id.get(channel_name, None)
|
211
|
+
if channel_id is None:
|
212
|
+
# no channel found
|
213
|
+
raise ValueError(f"Channel {channel_name} not found in Slack")
|
198
214
|
return channel_id
|
199
215
|
|
200
216
|
def _get_tags_from_message(self, blocks) -> List[str]:
|
@@ -222,9 +238,18 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
222
238
|
response = SocketModeResponse(envelope_id=req.envelope_id)
|
223
239
|
client.send_socket_mode_response(response)
|
224
240
|
|
241
|
+
if req.payload["event"]["ts"] in self._seen_msg_ids:
|
242
|
+
# already seen, pop it and move on
|
243
|
+
self._seen_msg_ids.remove(req.payload["event"]["ts"])
|
244
|
+
return
|
245
|
+
|
246
|
+
# else add it so we don't process it again
|
247
|
+
self._seen_msg_ids.add(req.payload["event"]["ts"])
|
248
|
+
|
225
249
|
if req.payload["event"]["type"] in ("message", "app_mention") and req.payload["event"].get("subtype") is None:
|
226
250
|
user, user_email = self._get_user_from_id(req.payload["event"]["user"])
|
227
251
|
channel, channel_type = self._get_channel_from_id(req.payload["event"]["channel"])
|
252
|
+
|
228
253
|
tags = self._get_tags_from_message(req.payload["event"]["blocks"])
|
229
254
|
slack_msg = SlackMessage(
|
230
255
|
user=user or "",
|
@@ -254,8 +279,8 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
254
279
|
# grab channel or DM
|
255
280
|
if hasattr(slack_msg, "channel_id") and slack_msg.channel_id:
|
256
281
|
channel_id = slack_msg.channel_id
|
282
|
+
|
257
283
|
elif hasattr(slack_msg, "channel") and slack_msg.channel:
|
258
|
-
# TODO DM
|
259
284
|
channel_id = self._get_channel_from_name(slack_msg.channel)
|
260
285
|
|
261
286
|
# pull text or reaction
|
@@ -266,6 +291,7 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
266
291
|
name=slack_msg.reaction,
|
267
292
|
timestamp=slack_msg.thread,
|
268
293
|
)
|
294
|
+
|
269
295
|
elif hasattr(slack_msg, "msg") and slack_msg.msg:
|
270
296
|
try:
|
271
297
|
# send text to channel
|
@@ -274,11 +300,10 @@ class SlackAdapterManager(AdapterManagerImpl):
|
|
274
300
|
text=getattr(slack_msg, "msg", ""),
|
275
301
|
)
|
276
302
|
except SlackApiError:
|
277
|
-
|
278
|
-
...
|
303
|
+
log.exception("Failed to send message to Slack")
|
279
304
|
else:
|
280
305
|
# cannot send empty message, log an error
|
281
|
-
log.
|
306
|
+
log.exception(f"Received malformed SlackMessage instance: {slack_msg}")
|
282
307
|
|
283
308
|
if not self._inqueue.empty():
|
284
309
|
# pull all SlackMessages from queue
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import csp
|
2
|
+
from csp import ts
|
3
|
+
|
4
|
+
from csp_adapter_slack import SlackAdapterConfig, SlackAdapterManager, SlackMessage
|
5
|
+
|
6
|
+
config = SlackAdapterConfig(
|
7
|
+
app_token=".app_token",
|
8
|
+
bot_token=".bot_token",
|
9
|
+
)
|
10
|
+
|
11
|
+
|
12
|
+
@csp.node
|
13
|
+
def add_reaction_when_mentioned(msg: ts[SlackMessage]) -> ts[SlackMessage]:
|
14
|
+
"""Add a reaction to every message that starts with hello."""
|
15
|
+
if msg.msg.lower().startswith("hello"):
|
16
|
+
return SlackMessage(
|
17
|
+
channel=msg.channel,
|
18
|
+
thread=msg.thread,
|
19
|
+
reaction="wave",
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
def graph():
|
24
|
+
# Create a DiscordAdapter object
|
25
|
+
adapter = SlackAdapterManager(config)
|
26
|
+
|
27
|
+
# Subscribe and unroll the messages
|
28
|
+
msgs = csp.unroll(adapter.subscribe())
|
29
|
+
|
30
|
+
# Print it out locally for debugging
|
31
|
+
csp.print("msgs", msgs)
|
32
|
+
|
33
|
+
# Add the reaction node
|
34
|
+
reactions = add_reaction_when_mentioned(msgs)
|
35
|
+
|
36
|
+
# Print it out locally for debugging
|
37
|
+
csp.print("reactions", reactions)
|
38
|
+
|
39
|
+
# Publish the reactions
|
40
|
+
adapter.publish(reactions)
|
41
|
+
|
42
|
+
|
43
|
+
if __name__ == "__main__":
|
44
|
+
csp.run(graph, realtime=True)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
__all__ = ("mention_user",)
|
2
|
+
|
3
|
+
|
4
|
+
def mention_user(userid: str) -> str:
|
5
|
+
"""Convenience method, more difficult to do in symphony but we want slack to be symmetric"""
|
6
|
+
if userid.startswith("<@") and userid.endswith(">"):
|
7
|
+
return userid
|
8
|
+
if userid.startswith("@"):
|
9
|
+
return f"<{userid}>"
|
10
|
+
return f"<@{userid}>"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
from typing import List
|
2
|
+
|
3
|
+
from csp.impl.struct import Struct
|
4
|
+
|
5
|
+
__all__ = ("SlackMessage",)
|
6
|
+
|
7
|
+
|
8
|
+
class SlackMessage(Struct):
|
9
|
+
user: str
|
10
|
+
"""name of the author of the message"""
|
11
|
+
|
12
|
+
user_email: str
|
13
|
+
"""email of the author of the message, if available"""
|
14
|
+
|
15
|
+
user_id: str
|
16
|
+
"""platform-specific id of the author of the message, if available"""
|
17
|
+
|
18
|
+
tags: List[str]
|
19
|
+
"""list of users tagged in the `msg` of the message"""
|
20
|
+
|
21
|
+
channel: str
|
22
|
+
"""name of the channel for the slack message, if available"""
|
23
|
+
|
24
|
+
channel_id: str
|
25
|
+
"""id of the channel for the slack message, if available"""
|
26
|
+
|
27
|
+
channel_type: str
|
28
|
+
"""type of the channel. either "message", "public", or "private" """
|
29
|
+
|
30
|
+
msg: str
|
31
|
+
"""parsed text of the message"""
|
32
|
+
|
33
|
+
reaction: str
|
34
|
+
"""emoji reaction to put on a thread. Exclusive with `msg`, requires `thread`"""
|
35
|
+
|
36
|
+
thread: str
|
37
|
+
"""thread to post msg under, or msg id on which to apply reaction"""
|
38
|
+
|
39
|
+
payload: dict
|
40
|
+
"""raw slack message payload"""
|
@@ -134,15 +134,15 @@ class TestSlack:
|
|
134
134
|
reqmock.type = "events_api"
|
135
135
|
reqmock.payload = payload
|
136
136
|
|
137
|
-
# mock out the user/
|
137
|
+
# mock out the user/channel lookup responses
|
138
138
|
mock_user_response = MagicMock(name="users_info_mock")
|
139
139
|
mock_user_response.status_code = 200
|
140
140
|
mock_user_response.data = {"user": {"profile": {"real_name_normalized": "johndoe", "email": "johndoe@some.email"}, "name": "blerg"}}
|
141
141
|
clientmock.return_value.web_client.users_info.return_value = mock_user_response
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
clientmock.return_value.web_client.conversations_info.return_value =
|
142
|
+
mock_channel_response = MagicMock(name="conversations_info_mock")
|
143
|
+
mock_channel_response.status_code = 200
|
144
|
+
mock_channel_response.data = {"channel": {"is_im": False, "is_private": True, "name": "a private channel"}}
|
145
|
+
clientmock.return_value.web_client.conversations_info.return_value = mock_channel_response
|
146
146
|
mock_list_response = MagicMock(name="conversations_list_mock")
|
147
147
|
mock_list_response.status_code = 200
|
148
148
|
mock_list_response.data = {
|
@@ -193,7 +193,7 @@ class TestSlack:
|
|
193
193
|
|
194
194
|
# check all inbound mocks got called
|
195
195
|
if payload == PUBLIC_CHANNEL_MENTION_PAYLOAD:
|
196
|
-
assert clientmock.return_value.web_client.users_info.call_count ==
|
196
|
+
assert clientmock.return_value.web_client.users_info.call_count == 3
|
197
197
|
else:
|
198
198
|
assert clientmock.return_value.web_client.users_info.call_count == 1
|
199
199
|
assert clientmock.return_value.web_client.conversations_info.call_count == 1
|
@@ -1,17 +1,17 @@
|
|
1
1
|
[build-system]
|
2
2
|
requires = [
|
3
|
-
"hatchling>=1.22.4,<1.
|
4
|
-
"pkginfo>=1.10,<1.
|
3
|
+
"hatchling>=1.22.4,<1.28",
|
4
|
+
"pkginfo>=1.10,<1.13",
|
5
5
|
]
|
6
6
|
build-backend = "hatchling.build"
|
7
7
|
|
8
8
|
[project]
|
9
9
|
name = "csp_adapter_slack"
|
10
10
|
description = "A csp adapter for slack"
|
11
|
-
version = "0.
|
11
|
+
version = "0.3.0"
|
12
12
|
readme = "README.md"
|
13
13
|
license = { file = "LICENSE" }
|
14
|
-
requires-python = ">=3.
|
14
|
+
requires-python = ">=3.9"
|
15
15
|
authors = [{name = "the csp authors", email = "CSPOpenSource@point72.com"}]
|
16
16
|
keywords = [
|
17
17
|
"csp",
|
@@ -25,7 +25,6 @@ classifiers = [
|
|
25
25
|
"Framework :: Jupyter",
|
26
26
|
"Programming Language :: Python",
|
27
27
|
"Programming Language :: Python :: 3",
|
28
|
-
"Programming Language :: Python :: 3.8",
|
29
28
|
"Programming Language :: Python :: 3.9",
|
30
29
|
"Programming Language :: Python :: 3.10",
|
31
30
|
"Programming Language :: Python :: 3.11",
|
@@ -43,11 +42,11 @@ dependencies = [
|
|
43
42
|
develop = [
|
44
43
|
"bump-my-version",
|
45
44
|
"check-manifest",
|
46
|
-
"codespell>=2.2.6,<2.
|
45
|
+
"codespell>=2.2.6,<2.5",
|
47
46
|
"hatchling",
|
48
47
|
"mdformat>=0.7.17,<0.8",
|
49
48
|
"mdformat-tables>=1,<1.1",
|
50
|
-
"ruff>=0.5,<0.
|
49
|
+
"ruff>=0.5,<0.12",
|
51
50
|
"twine>=5,<7",
|
52
51
|
# test
|
53
52
|
"pytest",
|
@@ -63,7 +62,7 @@ Repository = "https://github.com/point72/csp-adapter-slack"
|
|
63
62
|
Homepage = "https://github.com/point72/csp-adapter-slack"
|
64
63
|
|
65
64
|
[tool.bumpversion]
|
66
|
-
current_version = "0.
|
65
|
+
current_version = "0.3.0"
|
67
66
|
commit = true
|
68
67
|
tag = false
|
69
68
|
commit_args = "-s"
|
File without changes
|
File without changes
|