Skip to content

Commit 5392b8f

Browse files
Merge pull request #206 from symphony-youri/1.3-rc-1-3-5-release
Release 1.3.5
2 parents 131fb18 + 8073f6d commit 5392b8f

File tree

12 files changed

+188
-138
lines changed

12 files changed

+188
-138
lines changed

examples/ExpenseBot/listeners/processors/room_processor.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def __init__(self, bot_client):
1212
self.sym_message_parser = SymMessageParser()
1313
#hard code to the userId of bot you are using.
1414
self.bot_id = '349026222344891'
15-
self.default_message = self.default_message = self.message_formatter.format_message('type @karlPythonDemo help to view commands')
15+
self.default_message = self.message_formatter.format_message('type @karlPythonDemo help to view commands')
1616

1717
def process_room_message(self, msg):
1818
logging.debug('room_processor/process_room_message()')

requirements.txt

+30-28
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
1-
requests-pkcs12==1.9
1+
aiohttp==3.7.4.post0
2+
aioresponses==0.7.2
3+
async-timeout==3.0.1
4+
attrs==21.2.0
5+
beautifulsoup4==4.8.2
6+
certifi==2021.5.30
7+
cffi==1.14.5
8+
chardet==4.0.0
9+
cryptography==3.4.7
10+
defusedxml==0.7.1
11+
ecdsa==0.14.1
12+
idna==2.10
13+
Jinja2==2.11.3
14+
MarkupSafe==2.0.1
15+
multidict==5.1.0
16+
py==1.10.0
17+
pyasn1==0.4.8
18+
pycparser==2.20
19+
pyOpenSSL==20.0.1
20+
python-jose==3.2.0
21+
python-json-logger==0.1.11
22+
requests==2.25.1
23+
requests-mock==1.7.0
24+
requests-pkcs12==1.10
225
requests-toolbelt==0.9.1
26+
rsa==4.7.2
27+
six==1.16.0
28+
soupsieve==2.2.1
29+
typing-extensions==3.10.0.0
30+
urllib3==1.26.5
31+
yarl==1.6.3
332
yattag==1.12.2
4-
python-json-logger==0.1.11
5-
beautifulsoup4==4.8.0
6-
Jinja2==2.10.1
7-
defusedxml==0.6.0
8-
9-
rsa~=4.7
10-
pyasn1~=0.4.8
11-
six~=1.15.0
12-
ecdsa<0.15
13-
multidict~=4.7.6
14-
yarl~=1.4.2
15-
attrs~=19.3.0
16-
aiohttp>=3.7.4
17-
chardet~=3.0.4
18-
MarkupSafe~=1.1.1
19-
pycparser~=2.20
20-
idna~=2.9
21-
urllib3~=1.25.9
22-
certifi~=2020.4.5.2
23-
cffi~=1.14.0
24-
python-jose~=3.2.0
25-
requests~=2.24.0
26-
soupsieve~=2.0.1
27-
setuptools~=47.3.1
28-
aioresponses~=0.6.4
29-
pytest~=6.2.1
30-

setup.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def readme():
99
setuptools.setup(
1010
name="sym_api_client_python",
1111

12-
version="1.3.4",
12+
version="1.3.5",
1313
author="Symphony Platform Solutions",
1414
author_email="platformsolutions@symphony.com",
1515
description="Symphony REST API - Python Client",
@@ -20,19 +20,21 @@ def readme():
2020
packages=setuptools.find_packages(),
2121
install_requires=[
2222
'aiohttp',
23-
'aioresponses>=0.6.1',
23+
'aioresponses~=0.7.2',
2424
'pyOpenSSL',
2525
'rsa',
2626
'requests',
2727
'python-jose~=3.2.0',
28-
'python-json-logger==0.1.11',
29-
'beautifulsoup4==4.8.0',
30-
'Jinja2==2.10.1',
31-
'requests_pkcs12==1.9',
32-
'requests-toolbelt==0.9.1',
33-
'requests-mock>=1.7.0',
34-
'yattag==1.12.2',
35-
'defusedxml==0.6.0'
28+
'python-json-logger~=0.1.11',
29+
'beautifulsoup4~=4.8.0',
30+
'Jinja2~=2.11.3',
31+
'requests_pkcs12~=1.9',
32+
'requests-toolbelt~=0.9.1',
33+
'requests-mock~=1.7.0',
34+
'yattag~=1.12.2',
35+
'defusedxml~=0.7.1',
36+
'urllib3~=1.26.5',
37+
'py~=1.10.0'
3638
],
3739
tests_require=['pytest'],
3840
include_package_data=True,

sym_api_client_python/auth/rsa_auth.py

-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ def create_jwt(self):
8080
'exp': expiration_date
8181
}
8282
encoded = jwt.encode(payload, private_key, algorithm='RS512')
83-
f.close()
8483
return encoded
8584

8685
def session_authenticate(self):

sym_api_client_python/clients/message_client.py

+22-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import io
22
import logging
3+
from contextlib import contextmanager
34
from typing import Union
45

56
from .api_client import APIClient
@@ -12,6 +13,19 @@
1213
MESSAGE_CREATE = MESSAGE_STREAM_API + '/create'
1314

1415

16+
@contextmanager
17+
def open_file(file):
18+
if isinstance(file, io.IOBase):
19+
# already opened file
20+
yield file
21+
else:
22+
try:
23+
file_object = open(file, mode='rb')
24+
yield file_object
25+
finally:
26+
file_object.close()
27+
28+
1529
class MessageClient(APIClient):
1630

1731
def __init__(self, bot_client):
@@ -45,21 +59,14 @@ async def send_msg_async(self, stream_id, outbound_msg):
4559
url = MESSAGE_CREATE.format(stream_id=stream_id)
4660
return await self.bot_client.execute_rest_call_async('POST', url, files=outbound_msg)
4761

48-
def _data_and_headers_for_attachment(self, stream_id, msg, filename, attachment, aio=False):
62+
def _data_and_headers_for_attachment(self, stream_id, msg, filename, attachment_file, aio=False):
4963
"""Build an attachment out of either a path or a stream"""
5064
url = MESSAGE_CREATE.format(stream_id=stream_id)
5165

52-
try:
53-
attachment_file_object = open(attachment, 'rb')
54-
except TypeError:
55-
# If it doesn't support open treat it as a stream already
56-
attachment_file_object = attachment
57-
5866
# The below states that Content-Type for attachments should be 'file' which is almost
5967
# certainly wrong - it's not a valid MIME-type. text/plain seems right
6068
fields = {'message': msg,
61-
'attachment': (
62-
filename, attachment_file_object, "file")}
69+
'attachment': (filename, attachment_file, "file")}
6370

6471
parts = self.make_mulitpart_form(fields, aio=aio)
6572

@@ -76,8 +83,9 @@ def send_msg_with_attachment(self, stream_id, msg,
7683
A path to a file or a stream of bytes.
7784
"""
7885
logging.debug('MessageClient/send_msg_with_attachment()')
79-
parts = self._data_and_headers_for_attachment(stream_id, msg, filename, attachment)
80-
return self.bot_client.execute_rest_call("POST", **parts)
86+
with open_file(attachment) as attachment_file:
87+
parts = self._data_and_headers_for_attachment(stream_id, msg, filename, attachment_file)
88+
return self.bot_client.execute_rest_call("POST", **parts)
8189

8290
async def send_msg_with_attachment_async(self, stream_id, msg,
8391
filename, attachment: Union[str, io.BytesIO]):
@@ -86,9 +94,9 @@ async def send_msg_with_attachment_async(self, stream_id, msg,
8694
A path to a file or a stream of bytes.
8795
"""
8896
logging.debug('MessageClient/send_msg_with_attachment()')
89-
90-
parts = self._data_and_headers_for_attachment(stream_id, msg, filename, attachment, aio=True)
91-
return await self.bot_client.execute_rest_call_async('POST', **parts)
97+
with open_file(attachment) as attachment_file:
98+
parts = self._data_and_headers_for_attachment(stream_id, msg, filename, attachment_file, aio=True)
99+
return await self.bot_client.execute_rest_call_async('POST', **parts)
92100

93101
def get_msg_attachment(self, stream_id, msg_id, file_id):
94102
logging.debug('MessageClient/get_msg_attachment()')

sym_api_client_python/clients/user_client.py

-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import logging
2-
from .api_client import APIClient
3-
import logging
42

53
from .api_client import APIClient
64

sym_api_client_python/datafeed_event_service.py

+40-33
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from asyncio import CancelledError
99

10-
#TODO: These imports are duplicated over the abstract class to avoid errors in the Async version
10+
# TODO: These imports are duplicated over the abstract class to avoid errors in the Async version
1111
from .exceptions.UnauthorizedException import UnauthorizedException
1212
from .exceptions.APIClientErrorException import APIClientErrorException
1313
from .exceptions.DatafeedExpiredException import DatafeedExpiredException
@@ -215,13 +215,13 @@ async def deactivate_datafeed(self, wait_for_handler_completions=True):
215215
log.debug('AsyncDataFeedEventService/deactivate_datafeed()')
216216
if wait_for_handler_completions:
217217
log.debug('AsyncDataFeedEventService/deactivate_datafeed() --> '
218-
'Waiting for {} events to finish'.format(self.queue.qsize()))
218+
'Waiting for {} events to finish'.format(self.queue.qsize()))
219219
await self.queue.join()
220220
log.debug('AsyncDataFeedEventService/deactivate_datafeed() --> '
221-
'Deactivating')
221+
'Deactivating')
222222
else:
223223
log.debug('AsyncDataFeedEventService/deactivate_datafeed() --> '
224-
'{} events still being handled, deactivating anyway'.format(self.queue.qsize()))
224+
'{} events still being handled, deactivating anyway'.format(self.queue.qsize()))
225225

226226
if not self.stop:
227227
self.stop = True
@@ -314,25 +314,30 @@ def _process_full_trace(self, id):
314314
Use with messagedId if available
315315
"""
316316

317-
if self.trace_enabled:
318-
try:
319-
intermediates = self.trace_dict[id]
320-
assert len(intermediates) == 4
321-
trace = EventTrace(id, intermediates[0], intermediates[1], intermediates[2],
322-
intermediates[3])
323-
total_time = intermediates[3] - intermediates[0]
324-
time_in_bot = intermediates[3] - intermediates[1]
325-
326-
# This just writes out total seconds instead of formatting into minutes and hours
327-
# for a typical bot response this seems reasonable
328-
log.debug("Responded to message in: {:.4g}s. Including {:.4g}s inside the bot"
329-
.format(total_time.total_seconds(), time_in_bot.total_seconds()))
330-
if self.trace_recorder is not None:
331-
self.trace_recorder.append(trace)
332-
del self.trace_dict[id]
333-
except Exception as exc:
334-
log.error("Error while computing trace results for id: " + id)
335-
log.exception(exc)
317+
if not self.trace_enabled:
318+
return
319+
320+
try:
321+
intermediates = self.trace_dict[id]
322+
if len(intermediates) != 4:
323+
log.error("Error while computing trace results for id: " + id + ": trace item should have 4 elements")
324+
return
325+
326+
trace = EventTrace(id, intermediates[0], intermediates[1], intermediates[2],
327+
intermediates[3])
328+
total_time = intermediates[3] - intermediates[0]
329+
time_in_bot = intermediates[3] - intermediates[1]
330+
331+
# This just writes out total seconds instead of formatting into minutes and hours
332+
# for a typical bot response this seems reasonable
333+
log.debug("Responded to message in: {:.4g}s. Including {:.4g}s inside the bot"
334+
.format(total_time.total_seconds(), time_in_bot.total_seconds()))
335+
if self.trace_recorder is not None:
336+
self.trace_recorder.append(trace)
337+
del self.trace_dict[id]
338+
except Exception as exc:
339+
log.error("Error while computing trace results for id: " + id)
340+
log.exception(exc)
336341

337342
@staticmethod
338343
def _get_event_id(event):
@@ -348,16 +353,18 @@ def _add_trace(self, e_id, first_timestamp=None):
348353
349354
Use with messageId if available
350355
"""
351-
if self.trace_enabled:
352-
if first_timestamp is not None:
353-
self.trace_dict[e_id] = [make_datetime(first_timestamp)]
354-
try:
355-
self.trace_dict[e_id].append(datetime.datetime.utcnow())
356-
except KeyError:
357-
log.error(
358-
'Error making traces for {}. Has the same messageId appeared'
359-
'more than once?'.format(e_id)
360-
)
356+
if not self.trace_enabled:
357+
return
358+
359+
if first_timestamp is not None:
360+
self.trace_dict[e_id] = [make_datetime(first_timestamp)]
361+
try:
362+
self.trace_dict[e_id].append(datetime.datetime.utcnow())
363+
except KeyError:
364+
log.error(
365+
'Error making traces for {}. Has the same messageId appeared'
366+
'more than once?'.format(e_id)
367+
)
361368

362369
async def handle_events(self):
363370
"""For each event resolve its handler and add it to the queue to be processed"""

sym_api_client_python/processors/sym_elements_parser.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ def get_action_stream_id(self, elements_action_data):
6969
actionStream is where the formMessage is sent, this is a hidden stream
7070
so that the encryption context is between user and bot only and not everyone else on the room
7171
"""
72-
if elements_action_data['payload']['symphonyElementsAction']['actionStream'] != None and \
73-
elements_action_data['payload']['symphonyElementsAction']['actionStream']['streamId'] != None:
72+
if elements_action_data['payload']['symphonyElementsAction']['actionStream'] is not None and \
73+
elements_action_data['payload']['symphonyElementsAction']['actionStream']['streamId'] is not None:
7474
return elements_action_data['payload']['symphonyElementsAction']['actionStream']['streamId']
7575

7676
def get_form_message_id(self, elements_action_data):
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<messageML>
2-
<form id={{form_id}}>
2+
<form id="{{form_id}}">
33

44
</form>
55
</messageML>

0 commit comments

Comments
 (0)