incognia-python 2.0.0__tar.gz → 2.1.0__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 (34) hide show
  1. {incognia_python-2.0.0 → incognia_python-2.1.0}/PKG-INFO +1 -1
  2. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/api.py +20 -7
  3. incognia_python-2.1.0/incognia/datetime_util.py +9 -0
  4. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/PKG-INFO +1 -1
  5. incognia_python-2.1.0/requirements.txt +2 -0
  6. {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/test_api.py +81 -11
  7. incognia_python-2.0.0/incognia/datetime_util.py +0 -5
  8. incognia_python-2.0.0/requirements.txt +0 -2
  9. {incognia_python-2.0.0 → incognia_python-2.1.0}/.github/dependabot.yml +0 -0
  10. {incognia_python-2.0.0 → incognia_python-2.1.0}/.github/workflows/codeql.yaml +0 -0
  11. {incognia_python-2.0.0 → incognia_python-2.1.0}/.github/workflows/continuous.yaml +0 -0
  12. {incognia_python-2.0.0 → incognia_python-2.1.0}/.gitignore +0 -0
  13. {incognia_python-2.0.0 → incognia_python-2.1.0}/CODEOWNERS +0 -0
  14. {incognia_python-2.0.0 → incognia_python-2.1.0}/LICENSE.txt +0 -0
  15. {incognia_python-2.0.0 → incognia_python-2.1.0}/MANIFEST.in +0 -0
  16. {incognia_python-2.0.0 → incognia_python-2.1.0}/README.md +0 -0
  17. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/__init__.py +0 -0
  18. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/base_request.py +0 -0
  19. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/endpoints.py +0 -0
  20. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/exceptions.py +0 -0
  21. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/feedback_events.py +0 -0
  22. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/json_util.py +0 -0
  23. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/models.py +0 -0
  24. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/token_manager.py +0 -0
  25. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/SOURCES.txt +0 -0
  26. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/dependency_links.txt +0 -0
  27. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/not-zip-safe +0 -0
  28. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/requires.txt +0 -0
  29. {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/top_level.txt +0 -0
  30. {incognia_python-2.0.0 → incognia_python-2.1.0}/pyproject.toml +0 -0
  31. {incognia_python-2.0.0 → incognia_python-2.1.0}/setup.cfg +0 -0
  32. {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/__init__.py +0 -0
  33. {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/test_base_request.py +0 -0
  34. {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/test_token_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: incognia-python
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Python lightweight client library for Incognia APIs
5
5
  Home-page: https://github.com/inloco/incognia-python
6
6
  Author: Incognia
@@ -1,7 +1,7 @@
1
1
  import datetime as dt
2
2
  from typing import Optional, List
3
3
 
4
- from .datetime_util import total_milliseconds_since_epoch
4
+ from .datetime_util import total_milliseconds_since_epoch, has_timezone
5
5
  from .endpoints import Endpoints
6
6
  from .exceptions import IncogniaHTTPError, IncogniaError
7
7
  from .json_util import encode
@@ -50,33 +50,46 @@ class IncogniaAPI:
50
50
 
51
51
  def register_feedback(self,
52
52
  event: str,
53
- timestamp: dt.datetime,
53
+ timestamp: dt.datetime = None,
54
54
  external_id: Optional[str] = None,
55
55
  login_id: Optional[str] = None,
56
56
  payment_id: Optional[str] = None,
57
57
  signup_id: Optional[str] = None,
58
58
  account_id: Optional[str] = None,
59
59
  installation_id: Optional[str] = None,
60
- session_token: Optional[str] = None) -> None:
60
+ session_token: Optional[str] = None,
61
+ request_token: Optional[str] = None,
62
+ occurred_at: dt.datetime = None,
63
+ expires_at: dt.datetime = None) -> None:
61
64
  if not event:
62
65
  raise IncogniaError('event is required.')
63
- if not timestamp:
64
- raise IncogniaError('timestamp is required.')
66
+ if timestamp is not None and not has_timezone(timestamp):
67
+ raise IncogniaError('timestamp must have timezone')
68
+ if occurred_at is not None and not has_timezone(occurred_at):
69
+ raise IncogniaError('occurred_at must have timezone')
70
+ if expires_at is not None and not has_timezone(expires_at):
71
+ raise IncogniaError('expires_at must have timezone')
65
72
 
66
73
  try:
67
74
  headers = self.__get_authorization_header()
68
75
  headers.update(JSON_CONTENT_HEADER)
69
76
  body = {
70
77
  'event': event,
71
- 'timestamp': total_milliseconds_since_epoch(timestamp),
72
78
  'external_id': external_id,
73
79
  'login_id': login_id,
74
80
  'payment_id': payment_id,
75
81
  'signup_id': signup_id,
76
82
  'account_id': account_id,
77
83
  'installation_id': installation_id,
78
- 'session_token': session_token
84
+ 'session_token': session_token,
85
+ 'request_token': request_token
79
86
  }
87
+ if timestamp is not None:
88
+ body['timestamp'] = total_milliseconds_since_epoch(timestamp)
89
+ if occurred_at is not None:
90
+ body['occurred_at'] = occurred_at.isoformat()
91
+ if expires_at is not None:
92
+ body['expires_at'] = expires_at.isoformat()
80
93
  data = encode(body)
81
94
  return self.__request.post(Endpoints.FEEDBACKS, headers=headers, data=data)
82
95
 
@@ -0,0 +1,9 @@
1
+ import datetime as dt
2
+
3
+
4
+ def total_milliseconds_since_epoch(t: dt.datetime) -> int:
5
+ return int((t - dt.datetime.fromtimestamp(0, dt.timezone.utc)).total_seconds() * 1000.0)
6
+
7
+
8
+ def has_timezone(d: dt.datetime) -> bool:
9
+ return d.tzinfo is not None and d.tzinfo.utcoffset(d) is not None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: incognia-python
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Python lightweight client library for Incognia APIs
5
5
  Home-page: https://github.com/inloco/incognia-python
6
6
  Author: Incognia
@@ -0,0 +1,2 @@
1
+ requests~=2.32.3
2
+ setuptools~=71.1.0
@@ -16,6 +16,7 @@ class TestIncogniaAPI(TestCase):
16
16
  CLIENT_SECRET: Final[str] = 'ANY_SECRET'
17
17
  INSTALLATION_ID: Final[str] = 'ANY_INSTALLATION_ID'
18
18
  SESSION_TOKEN: Final[str] = 'ANY_SESSION_TOKEN'
19
+ REQUEST_TOKEN: Final[str] = 'ANY_REQUEST_TOKEN'
19
20
  INVALID_INSTALLATION_ID: Final[str] = 'INVALID_INSTALLATION_ID'
20
21
  INVALID_SESSION_TOKEN: Final[str] = 'INVALID_SESSION_TOKEN'
21
22
  ACCOUNT_ID: Final[str] = 'ANY_ACCOUNT_ID'
@@ -71,14 +72,30 @@ class TestIncogniaAPI(TestCase):
71
72
  CLIENT_ERROR_CODE: Final[int] = 400
72
73
  VALID_EVENT_FEEDBACK_TYPE: Final[str] = 'valid_event_feedback_type'
73
74
  INVALID_EVENT_FEEDBACK_TYPE: Final[str] = 'invalid_event_feedback_type'
74
- TIMESTAMP: Final[dt.datetime] = dt.datetime.utcfromtimestamp(0)
75
+ TIMESTAMP: Final[dt.datetime] = dt.datetime.now(dt.timezone.utc)
76
+ TIMESTAMP_WITHOUT_TIMEZONE: Final[dt.datetime] = dt.datetime.now()
77
+ LOGIN_ID: Final[str] = 'ANY_LOGIN_ID'
78
+ PAYMENT_ID: Final[str] = 'ANY_PAYMENT_ID'
75
79
  REGISTER_VALID_FEEDBACK_DATA: Final[bytes] = encode({
80
+ 'event': f'{VALID_EVENT_FEEDBACK_TYPE}'
81
+ })
82
+ REGISTER_VALID_FEEDBACK_DATA_FULL: Final[bytes] = encode({
76
83
  'event': f'{VALID_EVENT_FEEDBACK_TYPE}',
77
- 'timestamp': 0
84
+ 'external_id': f'{EXTERNAL_ID}',
85
+ 'login_id': f'{LOGIN_ID}',
86
+ 'payment_id': f'{PAYMENT_ID}',
87
+ 'signup_id': f'{SIGNUP_ID}',
88
+ 'account_id': f'{ACCOUNT_ID}',
89
+ 'installation_id': f'{INSTALLATION_ID}',
90
+ 'session_token': f'{SESSION_TOKEN}',
91
+ 'request_token': f'{REQUEST_TOKEN}',
92
+ 'timestamp': int((
93
+ TIMESTAMP - dt.datetime.fromtimestamp(0, dt.timezone.utc)).total_seconds() * 1000.0),
94
+ 'occurred_at': TIMESTAMP.isoformat(),
95
+ 'expires_at': TIMESTAMP.isoformat(),
78
96
  })
79
97
  REGISTER_INVALID_FEEDBACK_DATA: Final[bytes] = encode({
80
- 'event': f'{INVALID_EVENT_FEEDBACK_TYPE}',
81
- 'timestamp': 0
98
+ 'event': f'{INVALID_EVENT_FEEDBACK_TYPE}'
82
99
  })
83
100
  REGISTER_VALID_PAYMENT_DATA: Final[bytes] = encode({
84
101
  'type': 'payment',
@@ -185,32 +202,86 @@ class TestIncogniaAPI(TestCase):
185
202
  self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
186
203
  api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
187
204
 
188
- api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE, self.TIMESTAMP)
205
+ api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE)
189
206
 
190
207
  mock_token_manager_get.assert_called()
191
208
  mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
192
209
  headers=self.AUTH_AND_JSON_CONTENT_HEADERS,
193
210
  data=self.REGISTER_VALID_FEEDBACK_DATA)
194
211
 
212
+ @patch.object(BaseRequest, 'post')
213
+ @patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
214
+ def test_register_feedback_when_all_fields_are_valid_should_work(
215
+ self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
216
+ api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
217
+
218
+ api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE,
219
+ timestamp=self.TIMESTAMP,
220
+ occurred_at=self.TIMESTAMP,
221
+ expires_at=self.TIMESTAMP,
222
+ external_id=self.EXTERNAL_ID,
223
+ login_id=self.LOGIN_ID,
224
+ payment_id=self.PAYMENT_ID,
225
+ signup_id=self.SIGNUP_ID,
226
+ account_id=self.ACCOUNT_ID,
227
+ installation_id=self.INSTALLATION_ID,
228
+ session_token=self.SESSION_TOKEN,
229
+ request_token=self.REQUEST_TOKEN)
230
+
231
+ mock_token_manager_get.assert_called()
232
+ mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
233
+ headers=self.AUTH_AND_JSON_CONTENT_HEADERS,
234
+ data=self.REGISTER_VALID_FEEDBACK_DATA_FULL)
235
+
195
236
  @patch.object(BaseRequest, 'post')
196
237
  @patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
197
238
  def test_register_feedback_when_event_is_empty_should_raise_an_IncogniaError(
198
239
  self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
199
240
  api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
200
241
 
201
- self.assertRaises(IncogniaError, api.register_feedback, event='', timestamp=self.TIMESTAMP)
242
+ self.assertRaises(IncogniaError, api.register_feedback, event='')
243
+
244
+ mock_token_manager_get.assert_not_called()
245
+ mock_base_request_post.assert_not_called()
246
+
247
+ @patch.object(BaseRequest, 'post')
248
+ @patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
249
+ def test_register_feedback_when_timestamp_does_not_have_timezone_should_raise_IncogniaError(
250
+ self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
251
+ api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
252
+
253
+ self.assertRaises(IncogniaError,
254
+ api.register_feedback,
255
+ event=self.VALID_EVENT_FEEDBACK_TYPE,
256
+ timestamp=self.TIMESTAMP_WITHOUT_TIMEZONE)
257
+
258
+ mock_token_manager_get.assert_not_called()
259
+ mock_base_request_post.assert_not_called()
260
+
261
+ @patch.object(BaseRequest, 'post')
262
+ @patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
263
+ def test_register_feedback_when_occurred_at_does_not_have_timezone_should_raise_IncogniaError(
264
+ self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
265
+ api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
266
+
267
+ self.assertRaises(IncogniaError,
268
+ api.register_feedback,
269
+ event=self.VALID_EVENT_FEEDBACK_TYPE,
270
+ occurred_at=self.TIMESTAMP_WITHOUT_TIMEZONE)
202
271
 
203
272
  mock_token_manager_get.assert_not_called()
204
273
  mock_base_request_post.assert_not_called()
205
274
 
206
275
  @patch.object(BaseRequest, 'post')
207
276
  @patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
208
- def test_register_feedback_when_timestamp_is_none_should_raise_an_IncogniaError(
277
+ def test_register_feedback_when_expires_at_does_not_have_timezone_should_raise_IncogniaError(
209
278
  self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
210
279
  api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
211
280
 
212
- self.assertRaises(IncogniaError, api.register_feedback,
213
- event=self.VALID_EVENT_FEEDBACK_TYPE, timestamp=None)
281
+ self.assertRaises(IncogniaError,
282
+ api.register_feedback,
283
+ event=self.VALID_EVENT_FEEDBACK_TYPE,
284
+ expires_at=self.TIMESTAMP_WITHOUT_TIMEZONE)
214
285
 
215
286
  mock_token_manager_get.assert_not_called()
216
287
  mock_base_request_post.assert_not_called()
@@ -224,8 +295,7 @@ class TestIncogniaAPI(TestCase):
224
295
  api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
225
296
 
226
297
  self.assertRaises(IncogniaHTTPError, api.register_feedback,
227
- event=self.INVALID_EVENT_FEEDBACK_TYPE,
228
- timestamp=self.TIMESTAMP)
298
+ event=self.INVALID_EVENT_FEEDBACK_TYPE)
229
299
 
230
300
  mock_token_manager_get.assert_called()
231
301
  mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
@@ -1,5 +0,0 @@
1
- import datetime as dt
2
-
3
-
4
- def total_milliseconds_since_epoch(t: dt.datetime) -> int:
5
- return int((t - dt.datetime.utcfromtimestamp(0)).total_seconds() * 1000.0)
@@ -1,2 +0,0 @@
1
- requests~=2.32.3
2
- setuptools~=70.2.0