Skip to content

Commit 8d164f1

Browse files
authored
Make the Message attribute names align with the original json from received event (#252)
1 parent eacb42a commit 8d164f1

File tree

5 files changed

+43
-12
lines changed

5 files changed

+43
-12
lines changed

linebot/models/base.py

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

8888
@classmethod
89-
def new_from_json_dict(cls, data):
89+
def new_from_json_dict(cls, data, use_raw_message=False):
9090
"""Create a new instance from a dict.
9191
9292
:param data: JSON dict
93+
:param bool use_raw_message: Using original Message key as attribute
9394
"""
95+
if use_raw_message:
96+
return cls(use_raw_message=use_raw_message, **data)
97+
9498
new_data = {utils.to_snake_case(key): value
9599
for key, value in data.items()}
96100

@@ -117,7 +121,7 @@ def get_or_new_from_json_dict(data, cls):
117121

118122
@staticmethod
119123
def get_or_new_from_json_dict_with_types(
120-
data, cls_map, type_key='type'
124+
data, cls_map, type_key='type', use_raw_message=False
121125
):
122126
"""Get `cls` object w/ deserialization from json by using type key hint if needed.
123127
@@ -129,12 +133,13 @@ def get_or_new_from_json_dict_with_types(
129133
:param cls_map:
130134
:param type_key:
131135
:rtype: object
136+
:param bool use_raw_message: Using original Message key as attribute
132137
"""
133138
if isinstance(data, tuple(cls_map.values())):
134139
return data
135140
elif isinstance(data, dict):
136141
type_val = data[type_key]
137142
if type_val in cls_map:
138-
return cls_map[type_val].new_from_json_dict(data)
143+
return cls_map[type_val].new_from_json_dict(data, use_raw_message=use_raw_message)
139144

140145
return None

linebot/models/events.py

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

105105
def __init__(self, mode=None, timestamp=None, source=None, reply_token=None, message=None,
106-
**kwargs):
106+
use_raw_message=False, **kwargs):
107107
"""__init__ method.
108108
109109
:param str mode: Channel state
@@ -113,6 +113,7 @@ def __init__(self, mode=None, timestamp=None, source=None, reply_token=None, mes
113113
:param str reply_token: Reply token
114114
:param message: Message object
115115
:type message: T <= :py:class:`linebot.models.messages.Message`
116+
:param bool use_raw_message: Using original Message key as attribute
116117
:param kwargs:
117118
"""
118119
super(MessageEvent, self).__init__(
@@ -130,7 +131,7 @@ def __init__(self, mode=None, timestamp=None, source=None, reply_token=None, mes
130131
'location': LocationMessage,
131132
'sticker': StickerMessage,
132133
'file': FileMessage
133-
}
134+
}, use_raw_message=use_raw_message
134135
)
135136

136137

linebot/models/messages.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,28 @@
3535
class Message(with_metaclass(ABCMeta, Base)):
3636
"""Abstract Base Class of Message."""
3737

38-
def __init__(self, id=None, **kwargs):
38+
def __init__(self, id=None, use_raw_message=False, **kwargs):
3939
"""__init__ method.
4040
4141
:param str id: Message ID
42+
:param bool use_raw_message: Using original Message key as attribute
4243
:param kwargs:
4344
"""
4445
super(Message, self).__init__(**kwargs)
4546

47+
if use_raw_message:
48+
self.__dict__.update(kwargs)
49+
4650
self.type = None
4751
self.id = id
4852

53+
def __getitem__(self, key):
54+
"""__getitem__ method.
55+
56+
:param str key: Message key
57+
"""
58+
return self.__dict__.get(key, None)
59+
4960

5061
@deprecated(reason="Use 'from linebot.v3.webhooks import TextMessageContent' instead. See https://github.com/line/line-bot-sdk-python/blob/master/README.rst for more details.", version='3.0.0', category=LineBotSdkDeprecatedIn30) # noqa: E501
5162
class TextMessage(Message):

linebot/webhook.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,15 @@ def __init__(self, channel_secret):
138138
"""
139139
self.signature_validator = SignatureValidator(channel_secret)
140140

141-
def parse(self, body, signature, as_payload=False):
141+
def parse(self, body, signature, as_payload=False, use_raw_message=False):
142142
"""Parse webhook request body as text.
143143
144144
:param str body: Webhook request body (as text)
145145
:param str signature: X-Line-Signature value (as text)
146146
:param bool as_payload: (optional) True to return WebhookPayload object.
147147
:rtype: list[T <= :py:class:`linebot.models.events.Event`]
148148
| :py:class:`linebot.webhook.WebhookPayload`
149+
:param bool use_raw_message: Using original Message key as attribute
149150
:return: Events list, or WebhookPayload instance
150151
"""
151152
if not self.signature_validator.validate(body, signature):
@@ -157,7 +158,8 @@ def parse(self, body, signature, as_payload=False):
157158
for event in body_json['events']:
158159
event_type = event['type']
159160
if event_type == 'message':
160-
events.append(MessageEvent.new_from_json_dict(event))
161+
events.append(MessageEvent.new_from_json_dict(event,
162+
use_raw_message=use_raw_message))
161163
elif event_type == 'follow':
162164
events.append(FollowEvent.new_from_json_dict(event))
163165
elif event_type == 'unfollow':
@@ -244,13 +246,15 @@ def decorator(func):
244246

245247
return decorator
246248

247-
def handle(self, body, signature):
249+
def handle(self, body, signature, use_raw_message=False):
248250
"""Handle webhook.
249251
250252
:param str body: Webhook request body (as text)
251253
:param str signature: X-Line-Signature value (as text)
254+
:param bool use_raw_message: Using original Message key as attribute
252255
"""
253-
payload = self.parser.parse(body, signature, as_payload=True)
256+
payload = self.parser.parse(body, signature, as_payload=True,
257+
use_raw_message=use_raw_message)
254258

255259
for event in payload.events:
256260
func = None

tests/test_webhook.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import inspect
2121

2222
from linebot import (
23-
SignatureValidator, WebhookParser, WebhookHandler
23+
SignatureValidator, WebhookParser, WebhookHandler, utils
2424
)
2525
from linebot.models import (
2626
MessageEvent, FollowEvent, UnfollowEvent, JoinEvent,
@@ -614,6 +614,9 @@ def test_parse_webhook_req_without_destination(self):
614614
class TestWebhookHandler(unittest.TestCase):
615615
def setUp(self):
616616
self.handler = WebhookHandler('channel_secret')
617+
self.use_raw_message = True
618+
self.retrieve_attr_name = lambda x: x if self.use_raw_message \
619+
else utils.to_snake_case(x)
617620

618621
@self.handler.add(MessageEvent, message=TextMessage)
619622
def message_text(event, destination):
@@ -635,6 +638,13 @@ def message_sticker(event):
635638
self.assertEqual('message', event.type)
636639
self.assertEqual('sticker', event.message.type)
637640

641+
@self.handler.add(MessageEvent, message=FileMessage)
642+
def message_file(event):
643+
self.assertEqual('message', event.type)
644+
self.assertEqual('file', event.message.type)
645+
self.assertNotEqual(event.message[self.retrieve_attr_name("fileName")], None)
646+
self.assertNotEqual(event.message[self.retrieve_attr_name("fileSize")], None)
647+
638648
@self.handler.add(MessageEvent)
639649
def message(event):
640650
self.assertEqual('message', event.type)
@@ -680,7 +690,7 @@ def test_handler(self):
680690
# mock
681691
self.handler.parser.signature_validator.validate = lambda a, b: True
682692

683-
self.handler.handle(body, 'signature')
693+
self.handler.handle(body, 'signature', self.use_raw_message)
684694

685695

686696
class TestInvokeWebhookHandler(unittest.TestCase):

0 commit comments

Comments
 (0)