Skip to content

Commit 3fff2c7

Browse files
committed
Make the Message attribute names align with the original json from received event
1 parent 06e0eae commit 3fff2c7

File tree

5 files changed

+40
-12
lines changed

5 files changed

+40
-12
lines changed

linebot/models/base.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,15 @@ def as_json_dict(self):
8787
return data
8888

8989
@classmethod
90-
def new_from_json_dict(cls, data):
90+
def new_from_json_dict(cls, data, use_raw_message=False):
9191
"""Create a new instance from a dict.
9292
9393
:param data: JSON dict
94+
:param bool use_raw_message: Using original Message key as attribute
9495
"""
96+
if use_raw_message:
97+
return cls(use_raw_message=use_raw_message, **data)
98+
9599
new_data = {utils.to_snake_case(key): value
96100
for key, value in data.items()}
97101

@@ -118,7 +122,7 @@ def get_or_new_from_json_dict(data, cls):
118122

119123
@staticmethod
120124
def get_or_new_from_json_dict_with_types(
121-
data, cls_map, type_key='type'
125+
data, cls_map, type_key='type', use_raw_message=False
122126
):
123127
"""Get `cls` object w/ deserialization from json by using type key hint if needed.
124128
@@ -130,12 +134,13 @@ def get_or_new_from_json_dict_with_types(
130134
:param cls_map:
131135
:param type_key:
132136
:rtype: object
137+
:param bool use_raw_message: Using original Message key as attribute
133138
"""
134139
if isinstance(data, tuple(cls_map.values())):
135140
return data
136141
elif isinstance(data, dict):
137142
type_val = data[type_key]
138143
if type_val in cls_map:
139-
return cls_map[type_val].new_from_json_dict(data)
144+
return cls_map[type_val].new_from_json_dict(data, use_raw_message=use_raw_message)
140145

141146
return None

linebot/models/events.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class MessageEvent(Event):
7979
"""
8080

8181
def __init__(self, mode=None, timestamp=None, source=None, reply_token=None, message=None,
82-
**kwargs):
82+
use_raw_message=False, **kwargs):
8383
"""__init__ method.
8484
8585
:param str mode: Channel state
@@ -89,6 +89,7 @@ def __init__(self, mode=None, timestamp=None, source=None, reply_token=None, mes
8989
:param str reply_token: Reply token
9090
:param message: Message object
9191
:type message: T <= :py:class:`linebot.models.messages.Message`
92+
:param bool use_raw_message: Using original Message key as attribute
9293
:param kwargs:
9394
"""
9495
super(MessageEvent, self).__init__(
@@ -106,7 +107,7 @@ def __init__(self, mode=None, timestamp=None, source=None, reply_token=None, mes
106107
'location': LocationMessage,
107108
'sticker': StickerMessage,
108109
'file': FileMessage
109-
}
110+
}, use_raw_message=use_raw_message
110111
)
111112

112113

linebot/models/messages.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,28 @@
2626
class Message(with_metaclass(ABCMeta, Base)):
2727
"""Abstract Base Class of Message."""
2828

29-
def __init__(self, id=None, **kwargs):
29+
def __init__(self, id=None, use_raw_message=False, **kwargs):
3030
"""__init__ method.
3131
3232
:param str id: Message ID
33+
:param bool use_raw_message: Using original Message key as attribute
3334
:param kwargs:
3435
"""
3536
super(Message, self).__init__(**kwargs)
3637

38+
if use_raw_message:
39+
self.__dict__.update(kwargs)
40+
3741
self.type = None
3842
self.id = id
3943

44+
def __getitem__(self, key):
45+
"""__getitem__ method.
46+
47+
:param str key: Message key
48+
"""
49+
return self.__dict__.get(key, None)
50+
4051

4152
class TextMessage(Message):
4253
"""TextMessage.

linebot/webhook.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,15 @@ def __init__(self, channel_secret):
128128
"""
129129
self.signature_validator = SignatureValidator(channel_secret)
130130

131-
def parse(self, body, signature, as_payload=False):
131+
def parse(self, body, signature, as_payload=False, use_raw_message=False):
132132
"""Parse webhook request body as text.
133133
134134
:param str body: Webhook request body (as text)
135135
:param str signature: X-Line-Signature value (as text)
136136
:param bool as_payload: (optional) True to return WebhookPayload object.
137137
:rtype: list[T <= :py:class:`linebot.models.events.Event`]
138138
| :py:class:`linebot.webhook.WebhookPayload`
139+
:param bool use_raw_message: Using original Message key as attribute
139140
:return: Events list, or WebhookPayload instance
140141
"""
141142
if not self.signature_validator.validate(body, signature):
@@ -147,7 +148,7 @@ def parse(self, body, signature, as_payload=False):
147148
for event in body_json['events']:
148149
event_type = event['type']
149150
if event_type == 'message':
150-
events.append(MessageEvent.new_from_json_dict(event))
151+
events.append(MessageEvent.new_from_json_dict(event, use_raw_message=use_raw_message))
151152
elif event_type == 'follow':
152153
events.append(FollowEvent.new_from_json_dict(event))
153154
elif event_type == 'unfollow':
@@ -226,13 +227,14 @@ def decorator(func):
226227

227228
return decorator
228229

229-
def handle(self, body, signature):
230+
def handle(self, body, signature, use_raw_message=False):
230231
"""Handle webhook.
231232
232233
:param str body: Webhook request body (as text)
233234
:param str signature: X-Line-Signature value (as text)
235+
:param bool use_raw_message: Using original Message key as attribute
234236
"""
235-
payload = self.parser.parse(body, signature, as_payload=True)
237+
payload = self.parser.parse(body, signature, as_payload=True, use_raw_message=use_raw_message)
236238

237239
for event in payload.events:
238240
func = None

tests/test_webhook.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from builtins import open
2020

2121
from linebot import (
22-
SignatureValidator, WebhookParser, WebhookHandler
22+
SignatureValidator, WebhookParser, WebhookHandler, utils
2323
)
2424
from linebot.models import (
2525
MessageEvent, FollowEvent, UnfollowEvent, JoinEvent,
@@ -458,6 +458,8 @@ def test_parse_webhook_req_without_destination(self):
458458
class TestWebhookHandler(unittest.TestCase):
459459
def setUp(self):
460460
self.handler = WebhookHandler('channel_secret')
461+
self.use_raw_message = True
462+
self.retrive_attr_name = lambda x:x if self.use_raw_message else utils.to_snake_case(x)
461463

462464
@self.handler.add(MessageEvent, message=TextMessage)
463465
def message_text(event, destination):
@@ -479,6 +481,13 @@ def message_sticker(event):
479481
self.assertEqual('message', event.type)
480482
self.assertEqual('sticker', event.message.type)
481483

484+
@self.handler.add(MessageEvent, message=FileMessage)
485+
def message_file(event):
486+
self.assertEqual('message', event.type)
487+
self.assertEqual('file', event.message.type)
488+
self.assertNotEqual(event.message[self.retrive_attr_name("fileName")], None)
489+
self.assertNotEqual(event.message[self.retrive_attr_name("fileSize")], None)
490+
482491
@self.handler.add(MessageEvent)
483492
def message(event):
484493
self.assertEqual('message', event.type)
@@ -524,7 +533,7 @@ def test_handler(self):
524533
# mock
525534
self.handler.parser.signature_validator.validate = lambda a, b: True
526535

527-
self.handler.handle(body, 'signature')
536+
self.handler.handle(body, 'signature', self.use_raw_message)
528537

529538

530539
if __name__ == '__main__':

0 commit comments

Comments
 (0)