python-sdk-remote 0.0.127__tar.gz → 0.0.128__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.

Potentially problematic release.


This version of python-sdk-remote might be problematic. Click here for more details.

Files changed (21) hide show
  1. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/PKG-INFO +1 -1
  2. python_sdk_remote-0.0.128/README.md +11 -0
  3. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/constants.py +0 -9
  4. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/http_response.py +51 -16
  5. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/item.py +2 -3
  6. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/our_object.py +0 -9
  7. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/unified_json.py +0 -7
  8. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/utilities.py +32 -32
  9. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote.egg-info/PKG-INFO +1 -1
  10. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/setup.py +1 -1
  11. python_sdk_remote-0.0.127/README.md +0 -27
  12. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/pyproject.toml +0 -0
  13. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/__init__.py +0 -0
  14. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/mini_logger.py +0 -0
  15. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/valid_json_versions.py +0 -0
  16. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote/src/validate_environment.py +0 -0
  17. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote.egg-info/SOURCES.txt +0 -0
  18. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote.egg-info/dependency_links.txt +0 -0
  19. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote.egg-info/requires.txt +0 -0
  20. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/python_sdk_remote.egg-info/top_level.txt +0 -0
  21. {python_sdk_remote-0.0.127 → python_sdk_remote-0.0.128}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-sdk-remote
3
- Version: 0.0.127
3
+ Version: 0.0.128
4
4
  Summary: PyPI Package for Circles Python SDK Local Python
5
5
  Home-page: https://github.com/circles-zone/python-sdk-remote-python-package
6
6
  Author: Circles
@@ -0,0 +1,11 @@
1
+ # TODO: rewrite with more example
2
+
3
+ In serverless, use this decorator:
4
+ ```py
5
+ from python_sdk_remote.http_response import handler_decorator
6
+ from logger_local.Logger import Logger
7
+ logger = Logger.create_logger(object=your_logger_object)
8
+ @handler_decorator(logger=logger)
9
+ def my_handler(request_parameters: dict) -> dict:
10
+ # here you can use both camelCase and snake_case keys from request_parameters
11
+ ```
@@ -1,17 +1,8 @@
1
- import os
2
-
3
1
  from logger_local.LoggerComponentEnum import LoggerComponentEnum
4
2
 
5
3
  PYTHON_SDK_REMOTE_COMPONENT_ID = 184
6
4
  PYTHON_SDK_REMOTE_COMPONENT_NAME = 'python_sdk_remote'
7
5
 
8
- ENVIRONMENT_NAME = os.getenv("ENVIRONMENT_NAME")
9
- BRAND_NAME = os.getenv("BRAND_NAME")
10
- LOGZIO_TOKEN = os.getenv("LOGZIO_TOKEN")
11
- # TODO Shall Can we use python-sdk function to get the value from Environment?
12
- # TODO Shall we get the value from environment here of send the value to the function as @akiva-skolnik did?
13
- GOOGLE_PORT_FOR_AUTHENTICATION = os.getenv("PORT_FOR_AUTHENTICATION")
14
-
15
6
  OBJECT_TO_INSERT_CODE = {
16
7
  'component_id': PYTHON_SDK_REMOTE_COMPONENT_ID,
17
8
  'component_name': PYTHON_SDK_REMOTE_COMPONENT_NAME,
@@ -1,10 +1,10 @@
1
- import json
2
1
  import traceback
2
+ from functools import wraps
3
3
  from http import HTTPStatus
4
4
  from typing import Any
5
5
 
6
6
  from .mini_logger import MiniLogger as logger
7
- import warnings
7
+ from .utilities import camel_to_snake, snake_to_camel, to_dict, to_json
8
8
 
9
9
  HEADERS_KEY = 'headers'
10
10
  AUTHORIZATION_KEY = 'authorization'
@@ -17,26 +17,65 @@ AUTHORIZATION_PREFIX = 'Bearer '
17
17
  # TODO: add handler wrapper?
18
18
 
19
19
  def get_payload_dict_from_event(event: dict) -> dict:
20
- warnings.warn("DELETE get_payload_dict_from_event",DeprecationWarning,stacklevel=2)
21
20
  """Extracts params sent with payload"""
22
- return json.loads(event.get('body') or '{}')
21
+ return to_dict(event.get('body'))
23
22
 
24
23
 
25
24
  def get_path_parameters_dict_from_event(event: dict) -> dict:
26
- warnings.warn("DELETE get_path_parameters_dict_from_event",DeprecationWarning,stacklevel=2)
27
25
  """Extracts params sent implicitly: `url/param?test=5` -> param
28
26
  (when the path is defined with /{param})"""
29
27
  return event.get('pathParameters') or {}
30
28
 
31
29
 
32
30
  def get_query_string_parameters_from_event(event: dict) -> dict:
33
- warnings.warn("DELETE get_query_string_parameters_from_event",DeprecationWarning,stacklevel=2)
34
31
  """Extracts params sent explicitly: `url/test?a=1&b=2` -> {'a': '1', 'b': '2'}"""
35
32
  return event.get("queryStringParameters") or {} # params sent with ?a=1&b=2
36
33
 
37
34
 
35
+ def get_request_parameters_from_event(event: dict) -> dict:
36
+ """Extracts all params from the event object.
37
+ The order of precedence is: payload > path > query string
38
+ returns a dictionary with all the parameters, with both camelCase and snake_case keys."""
39
+ all_parameters_dict = get_payload_dict_from_event(event)
40
+ all_parameters_dict.update(get_path_parameters_dict_from_event(event))
41
+ all_parameters_dict.update(get_query_string_parameters_from_event(event))
42
+ all_parameters_dict = {camel_to_snake(key): value for key, value in all_parameters_dict.items()}
43
+ all_parameters_dict.update({snake_to_camel(key): value for key, value in all_parameters_dict.items()})
44
+ return all_parameters_dict
45
+
46
+
47
+ # TODO: test
48
+ def handler_decorator(logger):
49
+ """Decorator for AWS Lambda handler functions. It wraps the handler function with logging and error handling.
50
+ Usage:
51
+ from python_sdk_remote.http_response import handler_decorator
52
+ logger = ...
53
+ @handler_decorator(logger=logger)
54
+ def my_handler(request_parameters: dict) -> dict:
55
+ return {"message": "Hello, World!"}"""
56
+
57
+ def decorator(handler: callable) -> callable:
58
+ @wraps(handler)
59
+ def wrapper(event, context):
60
+ handler_response = None
61
+ try:
62
+ logger.start(object={"event": event, "context": context})
63
+ request_parameters = get_request_parameters_from_event(event)
64
+ body_result: dict = handler(request_parameters)
65
+ handler_response = create_ok_http_response(body_result)
66
+ except Exception as e:
67
+ handler_response = create_error_http_response(e)
68
+ finally:
69
+ logger.end(object={"handler_response": handler_response})
70
+ return handler_response
71
+
72
+ return wrapper
73
+
74
+ return decorator
75
+
76
+
77
+ # TODO: should we auto detect user_jwt if not provided?
38
78
  def create_authorization_http_headers(user_jwt: str) -> dict:
39
- warnings.warn("DELETE create_authorization_http_headers",DeprecationWarning,stacklevel=2)
40
79
  logger.start(object={"user_jwt": user_jwt})
41
80
  #TODO check the validity of user_jwt and it is not None and raise exception, please do the same in all other functions.
42
81
  authorization_http_headers = {
@@ -48,7 +87,6 @@ def create_authorization_http_headers(user_jwt: str) -> dict:
48
87
 
49
88
 
50
89
  def get_user_jwt_from_event(event: dict) -> str:
51
- warnings.warn("DELETE get_user_jwt_from_event",DeprecationWarning,stacklevel=2)
52
90
  logger.start(object={"event": event})
53
91
  auth_header = event.get(HEADERS_KEY, {}).get(AUTHORIZATION_KEY)
54
92
  if auth_header is None:
@@ -59,7 +97,6 @@ def get_user_jwt_from_event(event: dict) -> str:
59
97
 
60
98
 
61
99
  def create_return_http_headers() -> dict:
62
- warnings.warn("DELETE create_return_http_headers",DeprecationWarning,stacklevel=2)
63
100
  logger.start()
64
101
  # Adding "Access-Control-Allow-Origin" : "*" to take care of CORS from localhost
65
102
  # TODO Do we need to add those? In which cases? try adding crossDomain: true, to the request, 'Access-Control-Allow-Credentials': true to header
@@ -72,7 +109,6 @@ def create_return_http_headers() -> dict:
72
109
 
73
110
 
74
111
  def create_error_http_response(exception: Exception, status_code: HTTPStatus = HTTPStatus.BAD_REQUEST) -> dict:
75
- warnings.warn("DELETE create_error_http_response",DeprecationWarning,stacklevel=2)
76
112
  logger.start(object={"exception": exception})
77
113
  error_http_response = {
78
114
  "statusCode": status_code.value,
@@ -85,12 +121,12 @@ def create_error_http_response(exception: Exception, status_code: HTTPStatus = H
85
121
 
86
122
 
87
123
  def create_ok_http_response(body: Any) -> dict:
88
- warnings.warn("DELETE create_ok_http_response",DeprecationWarning,stacklevel=2)
89
124
  logger.start(object={"body": body})
125
+ # TODO: test sending statusCode/headers/body inside the body
90
126
  ok_http_response = {
91
- "statusCode": HTTPStatus.OK.value,
92
- "headers": create_return_http_headers(),
93
- "body": create_http_body(body)
127
+ "statusCode": body.get("statusCode") or HTTPStatus.OK.value,
128
+ "headers": body.get("headers") or create_return_http_headers(),
129
+ "body": create_http_body(body.get("body") or body)
94
130
  }
95
131
  logger.end(object={"ok_http_response": ok_http_response})
96
132
  return ok_http_response
@@ -98,10 +134,9 @@ def create_ok_http_response(body: Any) -> dict:
98
134
 
99
135
  # https://google.github.io/styleguide/jsoncstyleguide.xml?showone=Property_Name_Format#Property_Name_Format
100
136
  def create_http_body(body: Any) -> str:
101
- warnings.warn("DELETE create_http_body",DeprecationWarning,stacklevel=2)
102
137
  # TODO console.warning() if the body is not a valid camelCase JSON
103
138
  # https://stackoverflow.com/questions/17156078/converting-identifier-naming-between-camelcase-and-underscores-during-json-seria
104
139
  logger.start(object={"body": body})
105
- http_body = json.dumps(body)
140
+ http_body = to_json(body)
106
141
  logger.end(object={"http_body": http_body})
107
142
  return http_body
@@ -1,13 +1,12 @@
1
1
  from abc import abstractmethod
2
2
 
3
3
  from .our_object import OurObject
4
- import warnings
4
+
5
+
5
6
  class Item(OurObject):
6
7
  def __init__(self, **kwargs):
7
- warnings.warn("DELETE __init__",DeprecationWarning,stacklevel=2)
8
8
  super().__init__(**kwargs)
9
9
 
10
10
  @abstractmethod
11
11
  def get_id(self):
12
- warnings.warn("DELETE get_id",DeprecationWarning,stacklevel=2)
13
12
  raise NotImplementedError("Subclasses must implement the 'get_id' method.")
@@ -2,13 +2,11 @@ import json
2
2
  from abc import ABC, abstractmethod
3
3
 
4
4
  from .mini_logger import MiniLogger as logger
5
- import warnings
6
5
 
7
6
 
8
7
  # TODO Where are we using it? Shall we extend the usage of OurObject as the father of all our entities?
9
8
  class OurObject(ABC):
10
9
  def __init__(self, **kwargs):
11
- warnings.warn("DELETE __init__",DeprecationWarning,stacklevel=2)
12
10
  INIT_METHOD_NAME = '__init__'
13
11
  logger.start(INIT_METHOD_NAME, object={'kwargs': kwargs})
14
12
  self.kwargs = kwargs
@@ -16,13 +14,11 @@ class OurObject(ABC):
16
14
 
17
15
  @abstractmethod
18
16
  def get_name(self):
19
- warnings.warn("DELETE get_name",DeprecationWarning,stacklevel=2)
20
17
  """Returns the name of the object"""
21
18
  raise NotImplementedError(
22
19
  "Subclasses must implement the 'get_name' method.")
23
20
 
24
21
  def get(self, attr_name: str):
25
- warnings.warn("DELETE get",DeprecationWarning,stacklevel=2)
26
22
  """Returns the value of the attribute with the given name"""
27
23
  GET_METHOD_NAME = 'get'
28
24
  logger.start(GET_METHOD_NAME, object={'attr_name': attr_name})
@@ -32,17 +28,14 @@ class OurObject(ABC):
32
28
  return value
33
29
 
34
30
  def get_all_arguments(self):
35
- warnings.warn("DELETE get_all_arguments",DeprecationWarning,stacklevel=2)
36
31
  """Returns all the arguments passed to the constructor as a dictionary"""
37
32
  return getattr(self, 'kwargs', None)
38
33
 
39
34
  def to_json(self) -> str:
40
- warnings.warn("DELETE to_json",DeprecationWarning,stacklevel=2)
41
35
  """Returns a json string representation of this object"""
42
36
  return json.dumps(self.__dict__)
43
37
 
44
38
  def from_json(self, json_string: str) -> 'OurObject':
45
- warnings.warn("DELETE from_json",DeprecationWarning,stacklevel=2)
46
39
  """Returns an instance of the class from a json string"""
47
40
  FROM_JSON_METHOD_NAME = 'from_json'
48
41
  logger.start(FROM_JSON_METHOD_NAME,
@@ -53,13 +46,11 @@ class OurObject(ABC):
53
46
  return self
54
47
 
55
48
  def __eq__(self, other) -> bool:
56
- warnings.warn("DELETE __eq__",DeprecationWarning,stacklevel=2)
57
49
  """Checks if two objects are equal"""
58
50
  if not isinstance(other, OurObject):
59
51
  return False
60
52
  return self.__dict__ == other.__dict__
61
53
 
62
54
  def __ne__(self, other) -> bool:
63
- warnings.warn("DELETE __ne__",DeprecationWarning,stacklevel=2)
64
55
  """Checks if two objects are not equal"""
65
56
  return not self.__eq__(other)
@@ -1,11 +1,9 @@
1
1
  from .valid_json_versions import valid_json_versions
2
- import warnings
3
2
 
4
3
 
5
4
  # TODO Shall we merge it with the machine-learning-unified-json?
6
5
  class UnifiedJson:
7
6
  def __init__(self, data: dict, json_version: str):
8
- warnings.warn("DELETE __init__",DeprecationWarning,stacklevel=2)
9
7
  if json_version not in valid_json_versions:
10
8
  raise Exception(
11
9
  f"version {json_version} is not in valid_json_versions {valid_json_versions}, "
@@ -15,21 +13,16 @@ class UnifiedJson:
15
13
  self.data = data
16
14
 
17
15
  def get_unified_json(self):
18
- warnings.warn("DELETE get_unified_json",DeprecationWarning,stacklevel=2)
19
16
  return {"version": self.json_version, "data": self.data}
20
17
 
21
18
  def get_data(self):
22
- warnings.warn("DELETE get_data",DeprecationWarning,stacklevel=2)
23
19
  return self.data
24
20
 
25
21
  def get_json_version(self):
26
- warnings.warn("DELETE get_json_version",DeprecationWarning,stacklevel=2)
27
22
  return self.json_version
28
23
 
29
24
  def __str__(self):
30
- warnings.warn("DELETE __str__",DeprecationWarning,stacklevel=2)
31
25
  return self.get_unified_json()
32
26
 
33
27
  def __repr__(self):
34
- warnings.warn("DELETE __repr__",DeprecationWarning,stacklevel=2)
35
28
  return self.__str__()
@@ -1,21 +1,18 @@
1
+ import inspect
1
2
  import json
2
- import jwt
3
- import requests
4
- import re
5
3
  import os
6
4
  import random
5
+ import re
7
6
  from datetime import date, datetime, time, timedelta, timezone
7
+ from functools import lru_cache
8
8
  from urllib.parse import urlparse
9
- import warnings
10
9
 
10
+ import jwt
11
+ import requests
11
12
  from dotenv import load_dotenv
12
13
  from url_remote.environment_name_enum import EnvironmentName
13
14
 
14
15
  from .mini_logger import MiniLogger as logger
15
- from .http_response import (create_authorization_http_headers, # noqa - used for backwards compatibility
16
- get_user_jwt_from_event,
17
- create_return_http_headers, create_error_http_response, create_ok_http_response,
18
- create_http_body)
19
16
 
20
17
  load_dotenv()
21
18
  # TODO Let's do brainstorming on this
@@ -36,13 +33,11 @@ DEFAULT_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
36
33
 
37
34
 
38
35
  def append_if_not_exist(lst: list, item: object) -> None:
39
- warnings.warn("DELETE append_if_not_exist",DeprecationWarning,stacklevel=2)
40
36
  if item not in lst:
41
37
  lst.append(item)
42
38
 
43
39
 
44
40
  def to_dict(data: json or dict or None) -> dict:
45
- warnings.warn("DELETE to_dict",DeprecationWarning,stacklevel=2)
46
41
  if data is None:
47
42
  return {}
48
43
  if isinstance(data, dict):
@@ -51,7 +46,6 @@ def to_dict(data: json or dict or None) -> dict:
51
46
 
52
47
 
53
48
  def to_json(data: json or dict or None) -> json:
54
- warnings.warn("DELETE to_json",DeprecationWarning,stacklevel=2)
55
49
  if data is None:
56
50
  data = {}
57
51
  if isinstance(data, dict):
@@ -60,7 +54,6 @@ def to_json(data: json or dict or None) -> json:
60
54
 
61
55
 
62
56
  def timedelta_to_time_format(time_delta: timedelta) -> str:
63
- warnings.warn("DELETE timedelta_to_time_format",DeprecationWarning,stacklevel=2)
64
57
  """
65
58
  Convert a timedelta to a time format in HH:MM:SS.
66
59
 
@@ -97,7 +90,6 @@ def timedelta_to_time_format(time_delta: timedelta) -> str:
97
90
 
98
91
 
99
92
  def is_valid_time_range(time_range: tuple) -> bool:
100
- warnings.warn("DELETE is_valid_time_range",DeprecationWarning,stacklevel=2)
101
93
  """
102
94
  Validate that the time range is in the format 'HH:MM:SS'.
103
95
  """
@@ -124,7 +116,6 @@ def is_valid_time_range(time_range: tuple) -> bool:
124
116
  # TODO shall we also use Url type and not only str? - Strongly Type which I prefer
125
117
  # (if yes we should change it also in all the calls to this function)
126
118
  def validate_url(url: str):
127
- warnings.warn("DELETE validate_url",DeprecationWarning,stacklevel=2)
128
119
  logger.start(object={"url": url})
129
120
  if url is not None or url != "":
130
121
  parsed_url = urlparse(url)
@@ -136,7 +127,6 @@ def validate_url(url: str):
136
127
 
137
128
 
138
129
  def is_valid_date_range(date_range: tuple) -> bool:
139
- warnings.warn("DELETE is_valid_date_range",DeprecationWarning,stacklevel=2)
140
130
  """
141
131
  Validate that the date range is in the format 'YYYY-MM-DD'.
142
132
  """
@@ -155,7 +145,6 @@ def is_valid_date_range(date_range: tuple) -> bool:
155
145
 
156
146
 
157
147
  def is_valid_datetime_range(datetime_range: (datetime, datetime)) -> bool:
158
- warnings.warn("DELETE is_valid_datetime_range",DeprecationWarning,stacklevel=2)
159
148
  """
160
149
  Validate that the datetime range is in the format 'YYYY-MM-DD HH:MM:SS'.
161
150
  """
@@ -173,7 +162,6 @@ def is_valid_datetime_range(datetime_range: (datetime, datetime)) -> bool:
173
162
 
174
163
 
175
164
  def is_list_of_dicts(obj: object) -> bool:
176
- warnings.warn("DELETE is_list_of_dicts",DeprecationWarning,stacklevel=2)
177
165
  """
178
166
  Check if an object is a list of dictionaries.
179
167
 
@@ -218,7 +206,6 @@ def is_list_of_dicts(obj: object) -> bool:
218
206
 
219
207
 
220
208
  def is_time_in_time_range(check_time: time, time_range: tuple) -> bool:
221
- warnings.warn("DELETE is_time_in_time_range",DeprecationWarning,stacklevel=2)
222
209
  """
223
210
  Check if the given time is within the specified time range.
224
211
 
@@ -242,7 +229,6 @@ def is_time_in_time_range(check_time: time, time_range: tuple) -> bool:
242
229
 
243
230
 
244
231
  def is_date_in_date_range(check_date: date, date_range: tuple) -> bool:
245
- warnings.warn("DELETE is_date_in_date_range",DeprecationWarning,stacklevel=2)
246
232
  """
247
233
  Check if the given date is within the specified date range.
248
234
 
@@ -267,7 +253,6 @@ def is_date_in_date_range(check_date: date, date_range: tuple) -> bool:
267
253
 
268
254
 
269
255
  def is_datetime_in_datetime_range(check_datetime: datetime, datetime_range: (datetime, datetime)) -> bool:
270
- warnings.warn("DELETE is_datetime_in_datetime_range",DeprecationWarning,stacklevel=2)
271
256
  """
272
257
  Check if the given datetime is within the specified datetime range.
273
258
 
@@ -331,7 +316,6 @@ def get_dialog_jwt_secret_key() -> str:
331
316
 
332
317
 
333
318
  def encode_jwt(payload: dict, key: str) -> str:
334
- warnings.warn("DELETE encode_jwt",DeprecationWarning,stacklevel=2)
335
319
  """Example:
336
320
  payload = {
337
321
  "user_id": 123,
@@ -343,7 +327,6 @@ def encode_jwt(payload: dict, key: str) -> str:
343
327
 
344
328
 
345
329
  def decode_jwt(token: str, key: str) -> dict:
346
- warnings.warn("DELETE decode_jwt",DeprecationWarning,stacklevel=2)
347
330
  """key can be private / public"""
348
331
  return jwt.decode(token, key, algorithms=['HS256'])
349
332
 
@@ -369,44 +352,39 @@ def obfuscate_log_dict(log_dict: dict) -> dict:
369
352
  if isinstance(value, dict):
370
353
  obfuscated_log_dict[key] = obfuscate_log_dict(value)
371
354
  elif re.search(r'password|secret|token|jwt|e[\-_]?mail|phone|name|address|ssn', key, re.IGNORECASE):
372
- # TODO Maybe we can reveal a small part
355
+ # TODO Maybe we can reveal a small part
373
356
  obfuscated_log_dict[key] = "***"
374
357
  else:
375
358
  obfuscated_log_dict[key] = value
376
359
  return obfuscated_log_dict
377
360
 
361
+
378
362
  # TODO: add tests to the following functions
379
363
 
380
364
  def remove_digits(text: str) -> str:
381
- warnings.warn("DELETE remove_digits",DeprecationWarning,stacklevel=2)
382
365
  return ''.join(i for i in text if not i.isdigit())
383
366
 
384
367
 
385
368
  def generate_otp():
386
- warnings.warn("DELETE generate_otp",DeprecationWarning,stacklevel=2)
387
369
  """Generates a 6-digit OTP"""
388
370
  otp = random.randint(100000, 999999)
389
371
  return otp
390
372
 
391
373
 
392
374
  def get_current_datetime_string(datetime_format: str = DEFAULT_DATETIME_FORMAT, tz: timezone = None) -> str:
393
- warnings.warn("DELETE get_current_datetime_string",DeprecationWarning,stacklevel=2)
394
375
  current_datetime_string = datetime.now(tz).strftime(datetime_format)
395
376
  return current_datetime_string
396
377
 
397
378
 
398
379
  def datetime_from_str(date_str: str, datetime_format: str = DEFAULT_DATETIME_FORMAT) -> datetime:
399
- warnings.warn("DELETE datetime_from_str",DeprecationWarning,stacklevel=2)
400
380
  return datetime.strptime(date_str, datetime_format)
401
381
 
402
382
 
403
383
  def datetime_to_str(input_datetime: datetime, datetime_format: str = DEFAULT_DATETIME_FORMAT) -> str:
404
- warnings.warn("DELETE datetime_to_str",DeprecationWarning,stacklevel=2)
405
384
  return input_datetime.strftime(datetime_format)
406
385
 
407
386
 
408
387
  def validate_arguments(args: dict) -> None:
409
- warnings.warn("DELETE validate_arguments",DeprecationWarning,stacklevel=2)
410
388
  """
411
389
  Validate method arguments to ensure they are not None or ''
412
390
  :param args: arguments to be validated (usually locals())
@@ -418,7 +396,6 @@ def validate_arguments(args: dict) -> None:
418
396
 
419
397
 
420
398
  def reformat_time_string(input_str: str) -> str:
421
- warnings.warn("DELETE reformat_time_string",DeprecationWarning,stacklevel=2)
422
399
  """Example:
423
400
  "1234" -> "12:34:00:00"
424
401
  """
@@ -432,10 +409,33 @@ def reformat_time_string(input_str: str) -> str:
432
409
 
433
410
 
434
411
  def get_ip_v4():
435
- warnings.warn("DELETE get_ip_v4",DeprecationWarning,stacklevel=2)
436
412
  return requests.get('https://ipv4.seeip.org/jsonip').json()['ip']
437
413
 
438
414
 
439
415
  def get_ip_v6():
440
- warnings.warn("DELETE get_ip_v6",DeprecationWarning,stacklevel=2)
441
416
  return requests.get('https://api.seeip.org/jsonip').json()['ip']
417
+
418
+
419
+ def snake_to_camel(snake_str: str) -> str:
420
+ """Converts snake_case to camelCase."""
421
+ components = snake_str.split('_')
422
+ camel_str = components[0] + ''.join(x.title() for x in components[1:])
423
+ return camel_str
424
+
425
+
426
+ def camel_to_snake(camel_str: str) -> str:
427
+ """Converts camelCase to snake_case."""
428
+ snake_str = re.sub(r'(?<!^)(?=[A-Z])', '_', camel_str).lower()
429
+ return snake_str
430
+
431
+
432
+ @lru_cache(maxsize=64) # don't print the same warning multiple times
433
+ def deprecation_warning(old_name: str, new_name: str, start_date: date = None) -> None:
434
+ if start_date and start_date < date.today():
435
+ return
436
+ warnings_message = f"Please use {old_name} instead of {new_name}."
437
+ try:
438
+ warnings_message += " Called from: " + inspect.stack()[2].filename
439
+ except Exception:
440
+ pass
441
+ logger.warning(warnings_message)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-sdk-remote
3
- Version: 0.0.127
3
+ Version: 0.0.128
4
4
  Summary: PyPI Package for Circles Python SDK Local Python
5
5
  Home-page: https://github.com/circles-zone/python-sdk-remote-python-package
6
6
  Author: Circles
@@ -7,7 +7,7 @@ package_dir = PACKAGE_NAME.replace("-", "_")
7
7
  # python -m build needs pyproject.toml or setup.py
8
8
  setuptools.setup(
9
9
  name=PACKAGE_NAME,
10
- version='0.0.127', # https://pypi.org/project/python-sdk-remote/
10
+ version='0.0.128', # https://pypi.org/project/python-sdk-remote/
11
11
  author="Circles",
12
12
  author_email="info@circlez.ai",
13
13
  description="PyPI Package for Circles Python SDK Local Python",
@@ -1,27 +0,0 @@
1
- # python-sdk-package
2
-
3
- https://github.com/grosser/repo_dependency_graph Ruby, Graph the dependencies of your repositories
4
- https://github.com/thebjorn/pydeps Python
5
-
6
- To create local package and remote package layers (not to create GraphQL and REST-API layers)
7
-
8
- #database Python scripts in /db folder
9
- Please place <table-name>.py in /db<br>
10
- No need for seperate file for _ml table<br>
11
- Please delete the example file if not needed<br>
12
-
13
- # Create the files to create the database schema, tables, view and populate Meta Data and Test Date
14
-
15
- /db/<table-name>.py - CREATE SCHEMA ... CREATE TABLE ... CREATE VIEW ...<br>
16
- /db/<table-name>_insert.py to create records
17
-
18
- # Update the setup.py (i.e.name, version)
19
-
20
- # Please create test directory inside the directory of the project i.e. /<project-name>/tests
21
-
22
- # Update the serverless.yml in the root directory
23
-
24
- provider:
25
- stage: play1
26
-
27
- Update the endpoints in serverless.yml