sendbee-api 1.6.4__tar.gz → 1.7.2__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.
Files changed (52) hide show
  1. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/PKG-INFO +43 -30
  2. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/README.md +21 -20
  3. sendbee_api-1.7.2/pyproject.toml +46 -0
  4. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/automation/models.py +1 -0
  5. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/automation/query_params.py +1 -0
  6. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/bind.py +35 -15
  7. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/client.py +2 -1
  8. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/constants.py +26 -2
  9. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/conversations/models.py +2 -0
  10. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/conversations/query_params.py +2 -0
  11. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/debug.py +8 -1
  12. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/exceptions.py +3 -0
  13. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/formatter.py +16 -0
  14. sendbee_api-1.7.2/sendbee_api/rate_limit/client.py +26 -0
  15. sendbee_api-1.7.2/sendbee_api/rate_limit/models.py +10 -0
  16. sendbee_api-1.7.2/sendbee_api/rate_limit/query_params.py +5 -0
  17. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/response.py +14 -2
  18. sendbee_api-1.7.2/sendbee_api/teams/__init__.py +0 -0
  19. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api.egg-info/PKG-INFO +44 -31
  20. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api.egg-info/SOURCES.txt +15 -2
  21. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api.egg-info/requires.txt +6 -1
  22. sendbee_api-1.7.2/tests/test_auth.py +110 -0
  23. sendbee_api-1.7.2/tests/test_bind_request.py +476 -0
  24. sendbee_api-1.7.2/tests/test_client.py +67 -0
  25. sendbee_api-1.7.2/tests/test_endpoints_smoke.py +177 -0
  26. sendbee_api-1.7.2/tests/test_fields.py +105 -0
  27. sendbee_api-1.7.2/tests/test_formatter.py +79 -0
  28. sendbee_api-1.7.2/tests/test_models.py +99 -0
  29. sendbee_api-1.7.2/tests/test_query_params.py +59 -0
  30. sendbee_api-1.7.2/tests/test_response.py +112 -0
  31. sendbee_api-1.6.4/setup.py +0 -47
  32. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/LICENSE +0 -0
  33. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/__init__.py +0 -0
  34. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/auth.py +0 -0
  35. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/automation/__init__.py +0 -0
  36. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/automation/client.py +1 -1
  37. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/contacts/__init__.py +0 -0
  38. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/contacts/client.py +0 -0
  39. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/contacts/models.py +0 -0
  40. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/contacts/query_params.py +0 -0
  41. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/conversations/__init__.py +0 -0
  42. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/conversations/client.py +0 -0
  43. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/fields.py +0 -0
  44. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/models.py +0 -0
  45. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/query_params.py +0 -0
  46. {sendbee_api-1.6.4/sendbee_api/teams → sendbee_api-1.7.2/sendbee_api/rate_limit}/__init__.py +0 -0
  47. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/teams/client.py +0 -0
  48. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/teams/models.py +0 -0
  49. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api/teams/query_params.py +0 -0
  50. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api.egg-info/dependency_links.txt +0 -0
  51. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/sendbee_api.egg-info/top_level.txt +0 -0
  52. {sendbee_api-1.6.4 → sendbee_api-1.7.2}/setup.cfg +0 -0
@@ -1,14 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: sendbee_api
3
- Version: 1.6.4
3
+ Version: 1.7.2
4
4
  Summary: Python client SDK for Sendbee Public API
5
- Home-page: https://github.com/sendbee/sendbee-python-client
6
- Author: Sendbee ltd
7
- Author-email: info@sendbee.io
5
+ Author-email: Sendbee ltd <info@sendbee.io>
8
6
  License: MIT
7
+ Project-URL: Homepage, https://github.com/sendbee/sendbee-python-client
9
8
  Project-URL: Source, https://github.com/sendbee/sendbee-python-client
10
- Keywords: sendbee api python
11
- Platform: UNKNOWN
9
+ Keywords: sendbee,api,python
12
10
  Classifier: Intended Audience :: Developers
13
11
  Classifier: Topic :: Software Development :: Build Tools
14
12
  Classifier: License :: OSI Approved :: MIT License
@@ -16,30 +14,28 @@ Classifier: Programming Language :: Python :: 3.6
16
14
  Classifier: Programming Language :: Python :: 3.7
17
15
  Classifier: Programming Language :: Python :: 3.8
18
16
  Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Python: >=3.6
19
22
  Description-Content-Type: text/markdown
20
23
  License-File: LICENSE
21
-
22
- # Sendbee Python API Client
23
-
24
- ```
25
-
26
- .' '. __
27
- . . . (__\_
28
- . . . -{{_(|8)
29
- ' . . ' ' . . ' (__/
30
-
31
- ```
24
+ Requires-Dist: click>=7.0
25
+ Requires-Dist: requests>=2.20.0
26
+ Requires-Dist: dumpit>=0.5.0
27
+ Requires-Dist: aenum>=2.1.2
28
+ Requires-Dist: ujson<6,>=5.7.0
29
+ Requires-Dist: cryptography>=3.2
30
+ Requires-Dist: curlify>=2.2.1
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Requires-Dist: responses>=0.23; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # AI Number Python API Client
32
37
 
33
38
  [![PyPI version](https://badge.fury.io/py/sendbee-api.svg)](https://badge.fury.io/py/sendbee-api)
34
- [![Build Status](https://travis-ci.org/sendbee/sendbee-python-api-client.svg?branch=master)](https://travis-ci.org/sendbee/sendbee-python-api-client)
35
-
36
- ![GitHub issues](https://img.shields.io/github/issues/sendbee/sendbee-python-api-client.svg)
37
- ![GitHub closed issues](https://img.shields.io/github/issues-closed/sendbee/sendbee-python-api-client.svg)
38
- ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/sendbee/sendbee-python-api-client.svg)
39
-
40
- ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sendbee-api.svg)
41
- ![GitHub](https://img.shields.io/github/license/sendbee/sendbee-python-api-client.svg?color=blue)
42
- ![GitHub last commit](https://img.shields.io/github/last-commit/sendbee/sendbee-python-api-client.svg?color=blue)
43
39
 
44
40
  ## Table of contents
45
41
 
@@ -87,6 +83,7 @@ License-File: LICENSE
87
83
  #### Mics
88
84
 
89
85
  - [Pagination](#pagination)
86
+ - [API Rate Limit](#api-rate-limit)
90
87
  - [Raw response](#raw-response)
91
88
  - [Exception handling](#exception-handling)
92
89
  - [Authenticate webhook request](#authenticate-webhook-request)
@@ -594,7 +591,25 @@ while True:
594
591
  messages = api.messages(
595
592
  conversation_id='...', page=messages.next_page()
596
593
  )
597
- ```
594
+ ```
595
+
596
+ ### <a href='#api-rate-limit'>API Rate Limit</a>
597
+
598
+ A rate limit is the number of API calls a business number can make
599
+ within a given time period. If this limit is exceeded,
600
+ API requests are throttled, and will fail with 429 error response.
601
+
602
+ No matter how many API keys you make in your Sendbee account,
603
+ rate limit will always be counted within a business number.
604
+
605
+ ```python
606
+ from sendbee_api import SendbeeRequestApiException
607
+
608
+ try:
609
+ api.rate_limit_request_test()
610
+ except SendbeeRequestApiException as ex:
611
+ retry_after = ex.response.headers.get('Retry-After')
612
+ ```
598
613
 
599
614
  ### <a href='#raw-response'>Raw response</a>
600
615
 
@@ -673,5 +688,3 @@ api = SendbeeApi(
673
688
  Once you enabled the internal debug tool, every request to API will output various request and response data in standard output:
674
689
 
675
690
  ![Debugging](docs/images/debugging.png)
676
-
677
-
@@ -1,24 +1,6 @@
1
- # Sendbee Python API Client
2
-
3
- ```
4
-
5
- .' '. __
6
- . . . (__\_
7
- . . . -{{_(|8)
8
- ' . . ' ' . . ' (__/
9
-
10
- ```
1
+ # AI Number Python API Client
11
2
 
12
3
  [![PyPI version](https://badge.fury.io/py/sendbee-api.svg)](https://badge.fury.io/py/sendbee-api)
13
- [![Build Status](https://travis-ci.org/sendbee/sendbee-python-api-client.svg?branch=master)](https://travis-ci.org/sendbee/sendbee-python-api-client)
14
-
15
- ![GitHub issues](https://img.shields.io/github/issues/sendbee/sendbee-python-api-client.svg)
16
- ![GitHub closed issues](https://img.shields.io/github/issues-closed/sendbee/sendbee-python-api-client.svg)
17
- ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/sendbee/sendbee-python-api-client.svg)
18
-
19
- ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sendbee-api.svg)
20
- ![GitHub](https://img.shields.io/github/license/sendbee/sendbee-python-api-client.svg?color=blue)
21
- ![GitHub last commit](https://img.shields.io/github/last-commit/sendbee/sendbee-python-api-client.svg?color=blue)
22
4
 
23
5
  ## Table of contents
24
6
 
@@ -66,6 +48,7 @@
66
48
  #### Mics
67
49
 
68
50
  - [Pagination](#pagination)
51
+ - [API Rate Limit](#api-rate-limit)
69
52
  - [Raw response](#raw-response)
70
53
  - [Exception handling](#exception-handling)
71
54
  - [Authenticate webhook request](#authenticate-webhook-request)
@@ -573,7 +556,25 @@ while True:
573
556
  messages = api.messages(
574
557
  conversation_id='...', page=messages.next_page()
575
558
  )
576
- ```
559
+ ```
560
+
561
+ ### <a href='#api-rate-limit'>API Rate Limit</a>
562
+
563
+ A rate limit is the number of API calls a business number can make
564
+ within a given time period. If this limit is exceeded,
565
+ API requests are throttled, and will fail with 429 error response.
566
+
567
+ No matter how many API keys you make in your Sendbee account,
568
+ rate limit will always be counted within a business number.
569
+
570
+ ```python
571
+ from sendbee_api import SendbeeRequestApiException
572
+
573
+ try:
574
+ api.rate_limit_request_test()
575
+ except SendbeeRequestApiException as ex:
576
+ retry_after = ex.response.headers.get('Retry-After')
577
+ ```
577
578
 
578
579
  ### <a href='#raw-response'>Raw response</a>
579
580
 
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sendbee_api"
7
+ version = "1.7.2"
8
+ description = "Python client SDK for Sendbee Public API"
9
+ readme = "README.md"
10
+ requires-python = ">=3.6"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Sendbee ltd", email = "info@sendbee.io" }]
13
+ keywords = ["sendbee", "api", "python"]
14
+ classifiers = [
15
+ "Intended Audience :: Developers",
16
+ "Topic :: Software Development :: Build Tools",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3.6",
19
+ "Programming Language :: Python :: 3.7",
20
+ "Programming Language :: Python :: 3.8",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ ]
27
+ dependencies = [
28
+ "click>=7.0",
29
+ "requests>=2.20.0",
30
+ "dumpit>=0.5.0",
31
+ "aenum>=2.1.2",
32
+ "ujson>=5.7.0,<6",
33
+ "cryptography>=3.2",
34
+ "curlify>=2.2.1",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ dev = ["pytest", "responses>=0.23"]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/sendbee/sendbee-python-client"
42
+ Source = "https://github.com/sendbee/sendbee-python-client"
43
+
44
+ [tool.setuptools.packages.find]
45
+ include = ["sendbee_api*"]
46
+ exclude = ["tests*"]
@@ -1,6 +1,7 @@
1
1
  from sendbee_api.models import Model
2
2
  from sendbee_api.fields import TextField, BooleanField
3
3
 
4
+
4
5
  class ChatbotActivityStatus(Model):
5
6
  """Data model for chatbot status"""
6
7
 
@@ -7,6 +7,7 @@ class ChatbotActivity(QueryParams):
7
7
  conversation_id = 'conversation_id', 'Conversation UUID'
8
8
  active = 'active', 'Chatbot activity'
9
9
 
10
+
10
11
  class ChatbotActivityStatus(QueryParams):
11
12
  """Parameters for getting chatbot status for a conversation"""
12
13
 
@@ -23,6 +23,9 @@ def bind_request(**request_data):
23
23
  model = request_data.get(constants.ClientConst.MODEL)
24
24
  api_path = request_data.get(constants.RequestConst.API_PATH)
25
25
  formatter = request_data.get(constants.ClientConst.FORMATTER)
26
+ ignore_error = request_data.get(
27
+ constants.ClientConst.IGNORE_ERROR, False
28
+ )
26
29
  method = request_data.get(
27
30
  constants.RequestConst.METHOD, constants.RequestConst.GET
28
31
  )
@@ -187,8 +190,12 @@ def bind_request(**request_data):
187
190
  self.parameters[constants.RequestConst.QUERY]
188
191
  )
189
192
  self.debug.ok(constants.ResponseConst.RESPONSE_OBJECT, response)
193
+ self.debug.set_curl(
194
+ constants.DebugConst.CURL,
195
+ response.request
196
+ )
190
197
 
191
- return response.status_code, response.text
198
+ return response.status_code, response.headers, response.text
192
199
 
193
200
  elif self.method in [
194
201
  constants.RequestConst.POST,
@@ -210,14 +217,20 @@ def bind_request(**request_data):
210
217
  self.debug.ok('payload', self.parameters[
211
218
  constants.RequestConst.QUERY
212
219
  ])
213
- self.debug.ok(constants.ResponseConst.RESPONSE_OBJECT, response)
220
+ self.debug.ok(
221
+ constants.ResponseConst.RESPONSE_OBJECT, response
222
+ )
223
+ self.debug.set_curl(
224
+ constants.DebugConst.CURL,
225
+ response.request
226
+ )
214
227
 
215
- return response.status_code, response.text
228
+ return response.status_code, response.headers, response.text
216
229
 
217
230
  else:
218
231
  return constants.ResponseCode.NOT_FOUND, {}
219
232
 
220
- def _process_response(self, status_code, response):
233
+ def _process_response(self, status_code, response, headers):
221
234
  """
222
235
  Process response using models
223
236
  :status_code: Response status code
@@ -230,10 +243,11 @@ def bind_request(**request_data):
230
243
  formatter = FormatterFactory(constants.FormatterConst.JSON)\
231
244
  .get_formatter()
232
245
 
233
- response = Response(response, status_code, formatter, self)
246
+ response = Response(response, headers, status_code, formatter, self)
234
247
  formatted_data = response.formatted_data
235
248
 
236
- if status_code >= constants.ResponseCode.BAD_REQUEST:
249
+ if status_code >= constants.ResponseCode.BAD_REQUEST and \
250
+ self.ignore_error is False:
237
251
 
238
252
  if status_code == constants.ResponseCode.NOT_FOUND:
239
253
  error_msg = \
@@ -242,12 +256,18 @@ def bind_request(**request_data):
242
256
  error_msg = \
243
257
  constants.ResponseConst.DEFAULT_ERROR_MESSAGE
244
258
  else:
245
- error_msg = formatted_data.get(
246
- constants.ErrorConst.ERROR, {}
247
- ).get(
248
- constants.ErrorConst.DETAIL,
249
- constants.ErrorConst.UNRECOGNIZED_ERROR
250
- )
259
+ try:
260
+ error_msg = formatted_data.get(
261
+ constants.ErrorConst.ERROR, {}
262
+ ).get(
263
+ constants.ErrorConst.DETAIL,
264
+ constants.ErrorConst.UNRECOGNIZED_ERROR
265
+ )
266
+ except AttributeError:
267
+ error_msg = formatted_data.get(
268
+ constants.ErrorConst.DETAIL,
269
+ constants.ErrorConst.UNRECOGNIZED_ERROR
270
+ )
251
271
 
252
272
  self.debug.error(
253
273
  constants.ResponseConst.STATUS_CODE, status_code
@@ -255,7 +275,7 @@ def bind_request(**request_data):
255
275
  self.debug.error(
256
276
  constants.ResponseConst.RESPONSE, response.formatted_data
257
277
  )
258
- raise SendbeeRequestApiException(error_msg)
278
+ raise SendbeeRequestApiException(error_msg, response=response)
259
279
  else:
260
280
  self.debug.ok(constants.ResponseConst.STATUS_CODE, status_code)
261
281
  self.debug.ok(constants.ResponseConst.RESPONSE, response.raw_data)
@@ -287,8 +307,8 @@ def bind_request(**request_data):
287
307
  """
288
308
 
289
309
  self.url = self._prepare_url()
290
- status_code, response = self._do_request(self.url)
291
- return self._process_response(status_code, response)
310
+ status_code, headers, response = self._do_request(self.url)
311
+ return self._process_response(status_code, response, headers)
292
312
 
293
313
  def call(client, *path_params, **query_params):
294
314
  """
@@ -3,12 +3,13 @@ import click
3
3
  from sendbee_api.auth import SendbeeAuth
4
4
  from sendbee_api.teams.client import Teams
5
5
  from sendbee_api.contacts.client import Contacts
6
+ from sendbee_api.rate_limit.client import RateLimit
6
7
  from sendbee_api.automation.client import Automation
7
8
  from sendbee_api.conversations.client import Messages
8
9
  from sendbee_api.exceptions import SendbeeRequestApiException
9
10
 
10
11
 
11
- class Client(Contacts, Messages, Automation, Teams):
12
+ class Client(Contacts, Messages, Automation, Teams, RateLimit):
12
13
  """Main API class. Sets all API calls."""
13
14
 
14
15
  base_url = 'api-v2.sendbee.io'
@@ -1,3 +1,4 @@
1
+ from abc import ABCMeta
1
2
  from collections import namedtuple
2
3
 
3
4
 
@@ -38,9 +39,11 @@ ResponseConst = namedtuple(
38
39
 
39
40
  ClientConst = namedtuple(
40
41
  'ClientConst', [
41
- 'META', 'MODEL', 'MODELS', 'FORMATTER', 'DESCRIPTION', 'FORCE_SINGLE_MODEL_RESPONSE'
42
+ 'META', 'MODEL', 'MODELS', 'FORMATTER', 'DESCRIPTION',
43
+ 'FORCE_SINGLE_MODEL_RESPONSE', 'IGNORE_ERROR', 'HEADERS'
42
44
  ]
43
- )('meta', 'model', 'models', 'formatter', 'description', 'force_single_model_response')
45
+ )('meta', 'model', 'models', 'formatter', 'description',
46
+ 'force_single_model_response', 'ignore_error', 'headers')
44
47
 
45
48
  FormatterConst = namedtuple(
46
49
  'FormatterConst', ['JSON', 'FORMATTED']
@@ -61,3 +64,24 @@ MiscConst = namedtuple(
61
64
  ResponseDataConst = namedtuple(
62
65
  'ResponseDataConst', ['DATA', 'META']
63
66
  )('data', 'meta')
67
+
68
+
69
+ class ConstMeta(ABCMeta):
70
+ def __setattr__(self, name, value):
71
+ pass
72
+
73
+
74
+ class Const(metaclass=ConstMeta):
75
+ """Helper class """
76
+ __slots__ = ()
77
+
78
+
79
+ class DebugConst(Const):
80
+ PARAMETERS = 'parameters'
81
+ RESPONSE = 'response'
82
+ STATUS_CODE = 'status code'
83
+ FINAL_URL = 'final url'
84
+ HEADERS = 'headers'
85
+ METHOD = 'method'
86
+ QUERY_PARAMETERS = 'query parameters'
87
+ CURL = 'curl'
@@ -41,6 +41,8 @@ class SentMessage(Model):
41
41
 
42
42
  _conversation_id = TextField(index='id', desc='Conversation UUID')
43
43
  _message_id = TextField(index='message_id', desc='Message UUID')
44
+ _message_reference_id = TextField(index='message_reference_id',
45
+ desc='Message Reference UUID')
44
46
  _status = TextField(index='status', desc='Message status')
45
47
 
46
48
 
@@ -21,6 +21,7 @@ class SendTemplateMessage(QueryParams):
21
21
  prevent_bot_off = 'prevent_bot_off', 'Prevent turning-off chatbot'
22
22
  agent_id = 'agent_id', 'Assigned agent for the conversation'
23
23
  attachment = 'attachment', 'Attachment URL for media templates'
24
+ live_inbox = 'live_inbox', 'Trigger real-time events after sending'
24
25
 
25
26
 
26
27
  class SendMessage(QueryParams):
@@ -31,6 +32,7 @@ class SendMessage(QueryParams):
31
32
  media_url = 'media_url', 'Media URL for media message'
32
33
  prevent_bot_off = 'prevent_bot_off', 'Prevent turning-off chatbot'
33
34
  agent_id = 'agent_id', 'Assigned agent for the conversation'
35
+ live_inbox = 'live_inbox', 'Trigger real-time events after sending'
34
36
 
35
37
 
36
38
  class ListConversations(QueryParams):
@@ -1,5 +1,5 @@
1
1
  import click
2
- import pprint
2
+ import curlify
3
3
 
4
4
 
5
5
  STATUS_OK = 'ok'
@@ -25,6 +25,13 @@ class Debug:
25
25
  def error(self, key, value):
26
26
  self.record(key, value, STATUS_ERROR)
27
27
 
28
+ def set_curl(self, key, request):
29
+ if self.client.debug:
30
+ try:
31
+ self.ok(key, curlify.to_curl(request, compressed=False))
32
+ except UnicodeDecodeError:
33
+ self.ok(key, '__unable_to_decode__')
34
+
28
35
  def record(self, key, value, status):
29
36
  if self.client.debug:
30
37
  self.recorded_data[key] = {'value': value, 'status': status}
@@ -1,6 +1,9 @@
1
1
  class SendbeeException(Exception):
2
2
  """Handle All Sendbee Exceptions"""
3
3
 
4
+ def __init__(self, *args, **kwargs):
5
+ self.response = kwargs.get('response')
6
+
4
7
 
5
8
  class SendbeeRequestApiException(SendbeeException):
6
9
  """Handle Request Exceptions"""
@@ -29,6 +29,12 @@ class Formatter(metaclass=ABCMeta):
29
29
 
30
30
  return data
31
31
 
32
+ @abstractmethod
33
+ def _format_headers(self, data):
34
+ """Format method in formatter classes."""
35
+
36
+ return data
37
+
32
38
  def format_data(self, data):
33
39
  """Main format method."""
34
40
 
@@ -44,6 +50,11 @@ class Formatter(metaclass=ABCMeta):
44
50
 
45
51
  return self._format_warning(data)
46
52
 
53
+ def format_headers(self, data):
54
+ """Main format method."""
55
+
56
+ return self._format_headers(data)
57
+
47
58
  @staticmethod
48
59
  def _default_meta_data(total_results):
49
60
  """Create default data set if there aren't one from the response."""
@@ -106,6 +117,11 @@ class Json(Formatter):
106
117
  if isinstance(formatted_data, dict):
107
118
  return formatted_data.get(constants.WarningConst.WARNING)
108
119
 
120
+ def _format_headers(self, data):
121
+ """Transform raw data from server into python native type."""
122
+
123
+ return data
124
+
109
125
 
110
126
  class FormatterFactory:
111
127
  """Formatter factory class."""
@@ -0,0 +1,26 @@
1
+ from sendbee_api import constants
2
+ from sendbee_api.bind import bind_request
3
+ from sendbee_api.rate_limit import query_params
4
+ from sendbee_api.rate_limit.models import RateLimitError
5
+
6
+
7
+ class RateLimit:
8
+ """Api client for rete limit testing"""
9
+
10
+ rate_limit_error_test = bind_request(
11
+ api_path='/rate-limit/error-test',
12
+ model=RateLimitError,
13
+ query_parameters=query_params.RateLimitParams,
14
+ method=constants.RequestConst.GET,
15
+ # ignore_error=True,
16
+ description='Rate limit error test'
17
+ )
18
+
19
+ rate_limit_request_test = bind_request(
20
+ api_path='/rate-limit/request-test',
21
+ model=RateLimitError,
22
+ query_parameters=query_params.RateLimitParams,
23
+ method=constants.RequestConst.GET,
24
+ # ignore_error=True,
25
+ description='Rate limit request test'
26
+ )
@@ -0,0 +1,10 @@
1
+ from sendbee_api.models import Model
2
+ from sendbee_api.fields import TextField, BooleanField
3
+
4
+
5
+ class RateLimitError(Model):
6
+ """Data model for rate limit error"""
7
+
8
+ _detail = TextField(index='detail', desc='Message detail')
9
+ _error = BooleanField(index='error', desc='Error or not')
10
+ _type = TextField(index='type', desc='Message type')
@@ -0,0 +1,5 @@
1
+ from sendbee_api.query_params import QueryParams
2
+
3
+
4
+ class RateLimitParams(QueryParams):
5
+ """Parameters for rate limit testing"""
@@ -4,8 +4,9 @@ from sendbee_api import constants
4
4
  class Response:
5
5
  """Response object returned from API call."""
6
6
 
7
- def __init__(self, data, status_code, formatter, api_request):
7
+ def __init__(self, data, headers, status_code, formatter, api_request):
8
8
  self._data = data
9
+ self._headers = headers
9
10
  self._model = api_request.model
10
11
 
11
12
  self.api_reguest = api_request
@@ -16,7 +17,8 @@ class Response:
16
17
  constants.FormatterConst.FORMATTED: None,
17
18
  constants.ClientConst.MODELS: None,
18
19
  constants.ClientConst.META: None,
19
- constants.WarningConst.WARNING: None
20
+ constants.WarningConst.WARNING: None,
21
+ constants.ClientConst.HEADERS: None,
20
22
  }
21
23
 
22
24
  def __iter__(self):
@@ -63,6 +65,16 @@ class Response:
63
65
 
64
66
  return self._response_data[constants.ClientConst.META]
65
67
 
68
+ @property
69
+ def headers(self):
70
+ """Response headers."""
71
+
72
+ if not self._response_data[constants.ClientConst.HEADERS]:
73
+ self._response_data[constants.ClientConst.HEADERS] = \
74
+ self.formatter.format_headers(self._headers)
75
+
76
+ return self._response_data[constants.ClientConst.HEADERS]
77
+
66
78
  @property
67
79
  def warning(self):
68
80
  """Format warning data using selected formatter."""
File without changes