webex-message-handler 0.6.4__tar.gz → 0.6.6__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.
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/PKG-INFO +21 -1
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/README.md +20 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/pyproject.toml +1 -1
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/__init__.py +8 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/handler.py +48 -3
- webex_message_handler-0.6.6/src/webex_message_handler/mention_parser.py +59 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/mercury_socket.py +2 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/types.py +66 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/test_handler.py +5 -2
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/.gitignore +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/API.md +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/LICENSE +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/examples/basic_bot.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/device_manager.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/errors.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/id_utils.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/kms_client.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/logger.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/message_decryptor.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/url_validation.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/test-proxy.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/__init__.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/conftest.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/test_device_manager.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/test_id_utils.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/test_integration.py +0 -0
- {webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/tests/test_message_decryptor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webex-message-handler
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.6
|
|
4
4
|
Summary: Lightweight Webex Mercury WebSocket + KMS decryption for receiving bot messages without the full Webex SDK
|
|
5
5
|
Project-URL: Homepage, https://github.com/3rg0n/webex-message-handler
|
|
6
6
|
Project-URL: Repository, https://github.com/3rg0n/webex-message-handler
|
|
@@ -155,6 +155,26 @@ handler = WebexMessageHandler(
|
|
|
155
155
|
|
|
156
156
|
Requires: `pip install aiohttp-socks[asyncio]`
|
|
157
157
|
|
|
158
|
+
## Threading & Message IDs
|
|
159
|
+
|
|
160
|
+
Mercury uses raw activity UUIDs while the Webex REST API uses base64-encoded IDs. Use the conversion utilities to bridge them:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from webex_message_handler import to_rest_id, from_rest_id
|
|
164
|
+
|
|
165
|
+
@handler.on("message:created")
|
|
166
|
+
async def on_message(msg):
|
|
167
|
+
# Convert Mercury UUID to REST API ID for GET requests
|
|
168
|
+
rest_id = to_rest_id(msg.id, "MESSAGE")
|
|
169
|
+
|
|
170
|
+
# Thread replies: msg.parent_id contains the parent activity UUID
|
|
171
|
+
if msg.parent_id:
|
|
172
|
+
# Use msg.parent_id as parentId in POST /v1/messages
|
|
173
|
+
pass
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Resource types: `"MESSAGE"`, `"PEOPLE"`, `"ROOM"`.
|
|
177
|
+
|
|
158
178
|
## API Reference
|
|
159
179
|
|
|
160
180
|
### `WebexMessageHandler`
|
|
@@ -123,6 +123,26 @@ handler = WebexMessageHandler(
|
|
|
123
123
|
|
|
124
124
|
Requires: `pip install aiohttp-socks[asyncio]`
|
|
125
125
|
|
|
126
|
+
## Threading & Message IDs
|
|
127
|
+
|
|
128
|
+
Mercury uses raw activity UUIDs while the Webex REST API uses base64-encoded IDs. Use the conversion utilities to bridge them:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from webex_message_handler import to_rest_id, from_rest_id
|
|
132
|
+
|
|
133
|
+
@handler.on("message:created")
|
|
134
|
+
async def on_message(msg):
|
|
135
|
+
# Convert Mercury UUID to REST API ID for GET requests
|
|
136
|
+
rest_id = to_rest_id(msg.id, "MESSAGE")
|
|
137
|
+
|
|
138
|
+
# Thread replies: msg.parent_id contains the parent activity UUID
|
|
139
|
+
if msg.parent_id:
|
|
140
|
+
# Use msg.parent_id as parentId in POST /v1/messages
|
|
141
|
+
pass
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Resource types: `"MESSAGE"`, `"PEOPLE"`, `"ROOM"`.
|
|
145
|
+
|
|
126
146
|
## API Reference
|
|
127
147
|
|
|
128
148
|
### `WebexMessageHandler`
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "webex-message-handler"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.6"
|
|
8
8
|
description = "Lightweight Webex Mercury WebSocket + KMS decryption for receiving bot messages without the full Webex SDK"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/__init__.py
RENAMED
|
@@ -13,9 +13,11 @@ from .handler import WebexMessageHandler
|
|
|
13
13
|
from .id_utils import from_rest_id, to_rest_id
|
|
14
14
|
from .kms_client import KmsClient
|
|
15
15
|
from .logger import Logger, console_logger, noop_logger
|
|
16
|
+
from .mention_parser import ParsedMentions, parse_mentions
|
|
16
17
|
from .mercury_socket import MercurySocket
|
|
17
18
|
from .message_decryptor import MessageDecryptor
|
|
18
19
|
from .types import (
|
|
20
|
+
AttachmentAction,
|
|
19
21
|
ConnectionStatus,
|
|
20
22
|
DecryptedMessage,
|
|
21
23
|
DeletedMessage,
|
|
@@ -33,6 +35,7 @@ from .types import (
|
|
|
33
35
|
MercuryParent,
|
|
34
36
|
MercuryTarget,
|
|
35
37
|
NetworkMode,
|
|
38
|
+
RoomActivity,
|
|
36
39
|
WebexMessageHandlerConfig,
|
|
37
40
|
WebSocketFactory,
|
|
38
41
|
)
|
|
@@ -45,6 +48,9 @@ __all__ = [
|
|
|
45
48
|
"MercurySocket",
|
|
46
49
|
"KmsClient",
|
|
47
50
|
"MessageDecryptor",
|
|
51
|
+
# Mention parsing
|
|
52
|
+
"ParsedMentions",
|
|
53
|
+
"parse_mentions",
|
|
48
54
|
# Errors
|
|
49
55
|
"WebexError",
|
|
50
56
|
"AuthError",
|
|
@@ -71,6 +77,8 @@ __all__ = [
|
|
|
71
77
|
"DecryptedMessage",
|
|
72
78
|
"DeletedMessage",
|
|
73
79
|
"MembershipActivity",
|
|
80
|
+
"AttachmentAction",
|
|
81
|
+
"RoomActivity",
|
|
74
82
|
"HandlerStatus",
|
|
75
83
|
"ConnectionStatus",
|
|
76
84
|
# Networking types
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/handler.py
RENAMED
|
@@ -12,9 +12,11 @@ import aiohttp
|
|
|
12
12
|
from .device_manager import DeviceManager
|
|
13
13
|
from .kms_client import KmsClient
|
|
14
14
|
from .logger import Logger, noop_logger
|
|
15
|
+
from .mention_parser import parse_mentions
|
|
15
16
|
from .mercury_socket import MercurySocket
|
|
16
17
|
from .message_decryptor import MessageDecryptor
|
|
17
18
|
from .types import (
|
|
19
|
+
AttachmentAction,
|
|
18
20
|
ConnectionStatus,
|
|
19
21
|
DecryptedMessage,
|
|
20
22
|
DeletedMessage,
|
|
@@ -26,6 +28,7 @@ from .types import (
|
|
|
26
28
|
InjectedWebSocket,
|
|
27
29
|
MembershipActivity,
|
|
28
30
|
MercuryActivity,
|
|
31
|
+
RoomActivity,
|
|
29
32
|
WebexMessageHandlerConfig,
|
|
30
33
|
WebSocketFactory,
|
|
31
34
|
)
|
|
@@ -135,8 +138,12 @@ class WebexMessageHandler:
|
|
|
135
138
|
# Event listeners
|
|
136
139
|
self._listeners: dict[str, list[EventCallback]] = {
|
|
137
140
|
"message:created": [],
|
|
141
|
+
"message:updated": [],
|
|
138
142
|
"message:deleted": [],
|
|
139
143
|
"membership:created": [],
|
|
144
|
+
"attachmentAction:created": [],
|
|
145
|
+
"room:created": [],
|
|
146
|
+
"room:updated": [],
|
|
140
147
|
"connected": [],
|
|
141
148
|
"disconnected": [],
|
|
142
149
|
"reconnecting": [],
|
|
@@ -455,13 +462,14 @@ class WebexMessageHandler:
|
|
|
455
462
|
if len(self._recent_activity_ids) % 100 == 0:
|
|
456
463
|
self._sweep_old_activity_ids()
|
|
457
464
|
|
|
458
|
-
# message:created — verb=post + objectType=comment
|
|
459
|
-
if activity.verb
|
|
465
|
+
# message:created or message:updated — verb=post/update + objectType=comment
|
|
466
|
+
if activity.verb in ("post", "update") and activity.object.object_type == "comment":
|
|
460
467
|
if not self._message_decryptor:
|
|
461
468
|
self._logger.warning("Received activity but decryptor not initialized")
|
|
462
469
|
return
|
|
463
470
|
|
|
464
471
|
decrypted = await self._message_decryptor.decrypt_activity(activity)
|
|
472
|
+
mentions = parse_mentions(decrypted.object.content)
|
|
465
473
|
message = DecryptedMessage(
|
|
466
474
|
id=decrypted.id,
|
|
467
475
|
room_id=decrypted.target.id,
|
|
@@ -470,6 +478,9 @@ class WebexMessageHandler:
|
|
|
470
478
|
text=decrypted.object.display_name or "",
|
|
471
479
|
created=decrypted.published,
|
|
472
480
|
parent_id=decrypted.parent.id if decrypted.parent else None,
|
|
481
|
+
mentioned_people=mentions.mentioned_people,
|
|
482
|
+
mentioned_groups=mentions.mentioned_groups,
|
|
483
|
+
files=decrypted.object.files or [],
|
|
473
484
|
html=decrypted.object.content,
|
|
474
485
|
room_type=self._infer_room_type(decrypted),
|
|
475
486
|
raw=decrypted,
|
|
@@ -483,7 +494,8 @@ class WebexMessageHandler:
|
|
|
483
494
|
self._logger.debug(f"Ignoring self-message from bot ({self._bot_person_id})")
|
|
484
495
|
return
|
|
485
496
|
|
|
486
|
-
|
|
497
|
+
event_name = "message:updated" if activity.verb == "update" else "message:created"
|
|
498
|
+
self._emit(event_name, message)
|
|
487
499
|
return
|
|
488
500
|
|
|
489
501
|
# message:deleted — verb=delete + objectType=activity
|
|
@@ -515,6 +527,39 @@ class WebexMessageHandler:
|
|
|
515
527
|
raw=activity,
|
|
516
528
|
),
|
|
517
529
|
)
|
|
530
|
+
return
|
|
531
|
+
|
|
532
|
+
# attachmentAction:created — verb=cardAction + objectType=submit
|
|
533
|
+
if activity.verb == "cardAction" and activity.object.object_type == "submit":
|
|
534
|
+
self._emit(
|
|
535
|
+
"attachmentAction:created",
|
|
536
|
+
AttachmentAction(
|
|
537
|
+
id=activity.id,
|
|
538
|
+
message_id=activity.parent.id if activity.parent else "",
|
|
539
|
+
person_id=activity.actor.id,
|
|
540
|
+
person_email=activity.actor.email_address or "",
|
|
541
|
+
room_id=activity.target.id,
|
|
542
|
+
inputs=activity.object.inputs or {},
|
|
543
|
+
created=activity.published,
|
|
544
|
+
raw=activity,
|
|
545
|
+
),
|
|
546
|
+
)
|
|
547
|
+
return
|
|
548
|
+
|
|
549
|
+
# room:created or room:updated — verb=create/update + object.objectType=conversation
|
|
550
|
+
if activity.verb in ("create", "update") and activity.object.object_type == "conversation":
|
|
551
|
+
event_name = "room:created" if activity.verb == "create" else "room:updated"
|
|
552
|
+
self._emit(
|
|
553
|
+
event_name,
|
|
554
|
+
RoomActivity(
|
|
555
|
+
id=activity.id,
|
|
556
|
+
room_id=activity.target.id,
|
|
557
|
+
actor_id=activity.actor.id,
|
|
558
|
+
action="created" if activity.verb == "create" else "updated",
|
|
559
|
+
created=activity.published,
|
|
560
|
+
raw=activity,
|
|
561
|
+
),
|
|
562
|
+
)
|
|
518
563
|
|
|
519
564
|
@staticmethod
|
|
520
565
|
def _infer_room_type(activity: MercuryActivity) -> str | None:
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Parse Webex ``<spark-mention>`` tags from decrypted HTML."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class ParsedMentions:
|
|
11
|
+
"""Mentions extracted from message HTML."""
|
|
12
|
+
|
|
13
|
+
mentioned_people: list[str] = field(default_factory=list)
|
|
14
|
+
mentioned_groups: list[str] = field(default_factory=list)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
_MENTION_RE = re.compile(
|
|
18
|
+
r'<spark-mention[^>]*data-object-type="([^"]*)"[^>]*>', re.IGNORECASE
|
|
19
|
+
)
|
|
20
|
+
_PERSON_ID_RE = re.compile(r'data-object-id="([^"]*)"', re.IGNORECASE)
|
|
21
|
+
_GROUP_TYPE_RE = re.compile(r'data-group-type="([^"]*)"', re.IGNORECASE)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def parse_mentions(html: str | None) -> ParsedMentions:
|
|
25
|
+
"""Extract mentioned people and groups from decrypted HTML.
|
|
26
|
+
|
|
27
|
+
Parses ``<spark-mention>`` tags to find person UUIDs and group
|
|
28
|
+
mention types (e.g. ``"all"``). Duplicates are removed.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
html: Decrypted HTML content from a Webex message.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
ParsedMentions with ``mentioned_people`` and ``mentioned_groups``.
|
|
35
|
+
"""
|
|
36
|
+
result = ParsedMentions()
|
|
37
|
+
if not html:
|
|
38
|
+
return result
|
|
39
|
+
|
|
40
|
+
seen: set[str] = set()
|
|
41
|
+
|
|
42
|
+
for match in _MENTION_RE.finditer(html):
|
|
43
|
+
tag = match.group(0)
|
|
44
|
+
object_type = match.group(1)
|
|
45
|
+
|
|
46
|
+
if object_type == "person":
|
|
47
|
+
id_match = _PERSON_ID_RE.search(tag)
|
|
48
|
+
if id_match and id_match.group(1) and id_match.group(1) not in seen:
|
|
49
|
+
seen.add(id_match.group(1))
|
|
50
|
+
result.mentioned_people.append(id_match.group(1))
|
|
51
|
+
elif object_type == "groupMention":
|
|
52
|
+
group_match = _GROUP_TYPE_RE.search(tag)
|
|
53
|
+
if group_match and group_match.group(1):
|
|
54
|
+
key = f"group:{group_match.group(1)}"
|
|
55
|
+
if key not in seen:
|
|
56
|
+
seen.add(key)
|
|
57
|
+
result.mentioned_groups.append(group_match.group(1))
|
|
58
|
+
|
|
59
|
+
return result
|
|
@@ -411,6 +411,8 @@ def _parse_activity(raw: dict[str, Any]) -> MercuryActivity:
|
|
|
411
411
|
display_name=object_raw.get("displayName"),
|
|
412
412
|
content=object_raw.get("content"),
|
|
413
413
|
encryption_key_url=object_raw.get("encryptionKeyUrl"),
|
|
414
|
+
inputs=object_raw.get("inputs"),
|
|
415
|
+
files=object_raw.get("files"),
|
|
414
416
|
),
|
|
415
417
|
target=MercuryTarget(
|
|
416
418
|
id=target_raw.get("id", ""),
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/types.py
RENAMED
|
@@ -158,6 +158,11 @@ class MercuryObject:
|
|
|
158
158
|
display_name: str | None = None
|
|
159
159
|
content: str | None = None
|
|
160
160
|
encryption_key_url: str | None = None
|
|
161
|
+
inputs: dict[str, Any] | None = None
|
|
162
|
+
"""Card form input values (present on cardAction/submit activities)."""
|
|
163
|
+
|
|
164
|
+
files: list[str] | None = None
|
|
165
|
+
"""File URLs attached to the message (present on file-share messages)."""
|
|
161
166
|
|
|
162
167
|
|
|
163
168
|
@dataclass
|
|
@@ -222,6 +227,15 @@ class DecryptedMessage:
|
|
|
222
227
|
parent_id: str | None = None
|
|
223
228
|
"""Parent activity UUID for threaded replies. None if not a thread reply."""
|
|
224
229
|
|
|
230
|
+
mentioned_people: list[str] = field(default_factory=list)
|
|
231
|
+
"""Person UUIDs mentioned via @mention in the message."""
|
|
232
|
+
|
|
233
|
+
mentioned_groups: list[str] = field(default_factory=list)
|
|
234
|
+
"""Group mention types (e.g. 'all') in the message."""
|
|
235
|
+
|
|
236
|
+
files: list[str] = field(default_factory=list)
|
|
237
|
+
"""File URLs attached to the message."""
|
|
238
|
+
|
|
225
239
|
html: str | None = None
|
|
226
240
|
"""Decrypted HTML content (rich text messages)."""
|
|
227
241
|
|
|
@@ -270,6 +284,58 @@ class MembershipActivity:
|
|
|
270
284
|
"""Full raw activity for advanced use."""
|
|
271
285
|
|
|
272
286
|
|
|
287
|
+
@dataclass
|
|
288
|
+
class AttachmentAction:
|
|
289
|
+
"""An adaptive card submission from Mercury."""
|
|
290
|
+
|
|
291
|
+
id: str
|
|
292
|
+
"""Activity ID."""
|
|
293
|
+
|
|
294
|
+
message_id: str
|
|
295
|
+
"""ID of the message the card was attached to."""
|
|
296
|
+
|
|
297
|
+
person_id: str
|
|
298
|
+
"""ID of the person who submitted the card."""
|
|
299
|
+
|
|
300
|
+
person_email: str
|
|
301
|
+
"""Email of the person who submitted the card."""
|
|
302
|
+
|
|
303
|
+
room_id: str
|
|
304
|
+
"""Conversation/space ID."""
|
|
305
|
+
|
|
306
|
+
inputs: dict[str, Any]
|
|
307
|
+
"""Card form input values."""
|
|
308
|
+
|
|
309
|
+
created: str
|
|
310
|
+
"""ISO 8601 timestamp."""
|
|
311
|
+
|
|
312
|
+
raw: MercuryActivity | None = None
|
|
313
|
+
"""Full raw activity for advanced use."""
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@dataclass
|
|
317
|
+
class RoomActivity:
|
|
318
|
+
"""A room event from Mercury."""
|
|
319
|
+
|
|
320
|
+
id: str
|
|
321
|
+
"""Activity ID."""
|
|
322
|
+
|
|
323
|
+
room_id: str
|
|
324
|
+
"""Conversation/space ID."""
|
|
325
|
+
|
|
326
|
+
actor_id: str
|
|
327
|
+
"""ID of the person who performed the action."""
|
|
328
|
+
|
|
329
|
+
action: str
|
|
330
|
+
"""Room action: 'created' or 'updated'."""
|
|
331
|
+
|
|
332
|
+
created: str
|
|
333
|
+
"""ISO 8601 timestamp."""
|
|
334
|
+
|
|
335
|
+
raw: MercuryActivity | None = None
|
|
336
|
+
"""Full raw activity for advanced use."""
|
|
337
|
+
|
|
338
|
+
|
|
273
339
|
# --- Status ---
|
|
274
340
|
|
|
275
341
|
ConnectionStatus = Literal["connected", "connecting", "reconnecting", "disconnected"]
|
|
@@ -276,16 +276,19 @@ class TestMessageHandling:
|
|
|
276
276
|
async def test_ignores_non_message_activities(self):
|
|
277
277
|
handler = _make_handler()
|
|
278
278
|
handler._message_decryptor = MagicMock()
|
|
279
|
-
handler._message_decryptor.decrypt_activity = AsyncMock(return_value=_make_activity(verb="
|
|
279
|
+
handler._message_decryptor.decrypt_activity = AsyncMock(return_value=_make_activity(verb="acknowledge"))
|
|
280
280
|
|
|
281
281
|
messages = []
|
|
282
|
+
updated = []
|
|
282
283
|
deleted = []
|
|
283
284
|
handler.on("message:created", lambda msg: messages.append(msg))
|
|
285
|
+
handler.on("message:updated", lambda msg: updated.append(msg))
|
|
284
286
|
handler.on("message:deleted", lambda d: deleted.append(d))
|
|
285
287
|
|
|
286
|
-
await handler._handle_activity(_make_activity(verb="
|
|
288
|
+
await handler._handle_activity(_make_activity(verb="acknowledge"))
|
|
287
289
|
|
|
288
290
|
assert len(messages) == 0
|
|
291
|
+
assert len(updated) == 0
|
|
289
292
|
assert len(deleted) == 0
|
|
290
293
|
|
|
291
294
|
async def test_ignores_post_non_comment(self):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/errors.py
RENAMED
|
File without changes
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/id_utils.py
RENAMED
|
File without changes
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/kms_client.py
RENAMED
|
File without changes
|
{webex_message_handler-0.6.4 → webex_message_handler-0.6.6}/src/webex_message_handler/logger.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|