trd-utils 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl

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 trd-utils might be problematic. Click here for more details.

trd_utils/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- __version__ = "0.0.5"
2
+ __version__ = "0.0.7"
3
3
 
@@ -1,4 +1,6 @@
1
1
  from .base_model import BaseModel
2
2
 
3
3
 
4
- __all__ = ["BaseModel"]
4
+ __all__ = [
5
+ BaseModel,
6
+ ]
@@ -1,9 +1,10 @@
1
+ from decimal import Decimal
1
2
  import json
2
3
  from typing import (
3
4
  Union,
4
5
  get_type_hints,
5
6
  Any,
6
- get_args as get_type_args
7
+ get_args as get_type_args,
7
8
  )
8
9
 
9
10
  from trd_utils.html_utils.html_formats import camel_to_snake
@@ -19,6 +20,7 @@ ULTRA_LIST_ENABLED: bool = False
19
20
  # attribute names are converted to snake_case.
20
21
  SET_CAMEL_ATTR_NAMES = False
21
22
 
23
+
22
24
  def get_my_field_types(cls):
23
25
  type_hints = {}
24
26
  for current_cls in cls.__class__.__mro__:
@@ -27,24 +29,110 @@ def get_my_field_types(cls):
27
29
  type_hints.update(get_type_hints(current_cls))
28
30
  return type_hints
29
31
 
32
+
30
33
  def get_real_attr(cls, attr_name):
31
34
  if cls is None:
32
35
  return None
33
-
36
+
34
37
  if isinstance(cls, dict):
35
38
  return cls.get(attr_name, None)
36
39
 
37
40
  if hasattr(cls, attr_name):
38
41
  return getattr(cls, attr_name)
39
-
42
+
40
43
  return None
41
44
 
45
+
46
+ def is_any_type(target_type: type) -> bool:
47
+ return target_type == Any or target_type is type(None)
48
+
49
+
50
+ # TODO: add support for max_depth for this...
51
+ def value_to_normal_obj(value):
52
+ """
53
+ Converts a custom value, to a corresponding "normal object" which can be used
54
+ in dict.
55
+ """
56
+ if isinstance(value, BaseModel):
57
+ return value.to_dict()
58
+
59
+ if isinstance(value, list):
60
+ results = []
61
+ for current in value:
62
+ results.append(value_to_normal_obj(current))
63
+ return results
64
+
65
+ if isinstance(value, (int, str)) or value is None:
66
+ return value
67
+
68
+ if isinstance(value, Decimal):
69
+ return str(value)
70
+
71
+ if isinstance(value, dict):
72
+ result = {}
73
+ for inner_key, inner_value in value.items():
74
+ result[inner_key] = value_to_normal_obj(inner_value)
75
+
76
+ return result
77
+
78
+ raise TypeError(f"unsupported type provided: {type(value)}")
79
+
80
+
81
+ def generic_obj_to_value(
82
+ expected_type: type,
83
+ expected_type_args: tuple[type],
84
+ value: Any,
85
+ ):
86
+ """
87
+ Converts a normal JSON-compatible "object" to a customized python value.
88
+ """
89
+ if not expected_type_args:
90
+ expected_type_args = get_type_args(expected_type)
91
+
92
+ if isinstance(value, list):
93
+ result = []
94
+ for current in value:
95
+ result.append(generic_obj_to_value(
96
+ expected_type=expected_type_args[0],
97
+ expected_type_args=expected_type_args[1:],
98
+ value=current,
99
+ ))
100
+ return result
101
+
102
+ expected_type_name = getattr(expected_type, "__name__", None)
103
+ if expected_type_name == "dict" and isinstance(value, dict):
104
+ result = {}
105
+ for inner_key, inner_value in value.items():
106
+ result[expected_type_args[0](inner_key)] = generic_obj_to_value(
107
+ expected_type=expected_type_args[1],
108
+ expected_type_args=expected_type_args[1:],
109
+ value=inner_value,
110
+ )
111
+ return result
112
+
113
+ if isinstance(value, dict) and issubclass(expected_type, BaseModel):
114
+ if len(expected_type_args) > 1:
115
+ raise ValueError(
116
+ "unsupported operation: at this time we cannot have"
117
+ " expected type args at all...",
118
+ )
119
+ return expected_type(**value)
120
+
121
+ if not expected_type_args:
122
+ if isinstance(value, expected_type):
123
+ return value
124
+ return expected_type(value)
125
+
126
+ raise TypeError(f"unsupported type: {type(value)}")
127
+
128
+
42
129
  class UltraList(list):
43
130
  def __getattr__(self, attr):
44
131
  if len(self) == 0:
45
132
  return None
46
133
  return UltraList([get_real_attr(item, attr) for item in self])
47
134
 
135
+
48
136
  def convert_to_ultra_list(value: Any) -> UltraList:
49
137
  if not value:
50
138
  return UltraList()
@@ -61,7 +149,7 @@ def convert_to_ultra_list(value: Any) -> UltraList:
61
149
  return tuple(convert_to_ultra_list(v) for v in value)
62
150
  elif isinstance(value, set):
63
151
  return {convert_to_ultra_list(v) for v in value}
64
-
152
+
65
153
  for attr, attr_value in get_my_field_types(value).items():
66
154
  if isinstance(attr_value, list):
67
155
  setattr(value, attr, convert_to_ultra_list(getattr(value, attr)))
@@ -70,6 +158,7 @@ def convert_to_ultra_list(value: Any) -> UltraList:
70
158
  except Exception:
71
159
  return value
72
160
 
161
+
73
162
  class BaseModel:
74
163
  def __init__(self, **kwargs):
75
164
  annotations = get_my_field_types(self)
@@ -83,62 +172,79 @@ class BaseModel:
83
172
  # just ignore and continue
84
173
  annotations[key] = Any
85
174
  annotations[corrected_key] = Any
86
-
175
+
87
176
  expected_type = annotations[corrected_key]
88
177
  if hasattr(self, "_get_" + corrected_key + "_type"):
89
178
  try:
90
- overridden_type = getattr(self, "_get_" + corrected_key + "_type")(kwargs)
179
+ overridden_type = getattr(self, "_get_" + corrected_key + "_type")(
180
+ kwargs
181
+ )
91
182
  if overridden_type:
92
183
  expected_type = overridden_type
93
184
  except Exception:
94
185
  pass
95
-
96
- is_optional_type = getattr(expected_type, '_name', None) == 'Optional'
186
+
187
+ expected_type_args = get_type_args(expected_type)
188
+ expected_type_name = getattr(expected_type, "__name__", None)
189
+ is_optional_type = expected_type_name == "Optional"
190
+ is_dict_type = expected_type_name == "dict"
97
191
  # maybe in the future we can have some other usages for is_optional_type
98
192
  # variable or something like that.
99
193
  if is_optional_type:
100
194
  try:
101
- expected_type = get_type_args(expected_type)[0]
195
+ expected_type = expected_type_args[0]
102
196
  except Exception:
103
197
  # something went wrong, just ignore and continue
104
198
  expected_type = Any
105
-
199
+
200
+ if value is None:
201
+ # just skip...
202
+ pass
203
+ elif isinstance(value, dict) and is_dict_type:
204
+ value = generic_obj_to_value(
205
+ expected_type=expected_type,
206
+ expected_type_args=expected_type_args,
207
+ value=value,
208
+ )
209
+
106
210
  # Handle nested models
107
- if isinstance(value, dict) and issubclass(expected_type, BaseModel):
211
+ elif isinstance(value, dict) and issubclass(expected_type, BaseModel):
108
212
  value = expected_type(**value)
109
-
213
+
110
214
  elif isinstance(value, list):
111
- type_args = get_type_args(expected_type)
112
- if not type_args:
215
+ if not expected_type_args:
113
216
  # if it's Any, it means we shouldn't really care about the type
114
217
  if expected_type != Any:
115
218
  value = expected_type(value)
116
219
  else:
117
- # Handle list of nested models
118
- nested_type = type_args[0]
119
- if issubclass(nested_type, BaseModel):
120
- value = [nested_type(**item) for item in value]
121
-
220
+ value = generic_obj_to_value(
221
+ expected_type=expected_type,
222
+ expected_type_args=expected_type_args,
223
+ value=value,
224
+ )
225
+
122
226
  if ULTRA_LIST_ENABLED and isinstance(value, list):
123
227
  value = convert_to_ultra_list(value)
124
-
228
+
125
229
  # Type checking
126
- elif expected_type != Any and not isinstance(value, expected_type):
230
+ elif not (is_any_type(expected_type) or isinstance(value, expected_type)):
127
231
  try:
128
232
  value = expected_type(value)
129
233
  except Exception:
130
- raise TypeError(f"Field {corrected_key} must be of type {expected_type}," +
131
- f" but it's {type(value)}")
132
-
234
+ raise TypeError(
235
+ f"Field {corrected_key} must be of type {expected_type},"
236
+ + f" but it's {type(value)}"
237
+ )
238
+
133
239
  setattr(self, corrected_key, value)
134
240
  if SET_CAMEL_ATTR_NAMES and key != corrected_key:
135
241
  setattr(self, key, value)
136
-
242
+
137
243
  # Check if all required fields are present
138
244
  # for field in self.__annotations__:
139
245
  # if not hasattr(self, field):
140
246
  # raise ValueError(f"Missing required field: {field}")
141
-
247
+
142
248
  @classmethod
143
249
  def deserialize(cls, json_data: Union[str, dict]):
144
250
  if isinstance(json_data, str):
@@ -147,3 +253,29 @@ class BaseModel:
147
253
  data = json_data
148
254
  return cls(**data)
149
255
 
256
+ def serialize(
257
+ self,
258
+ separators=(",", ":"),
259
+ ensure_ascii=True,
260
+ sort_keys=True,
261
+ ) -> bytes:
262
+ return json.dumps(
263
+ obj=self.to_dict(),
264
+ ensure_ascii=ensure_ascii,
265
+ separators=separators,
266
+ sort_keys=sort_keys,
267
+ )
268
+
269
+ def to_dict(self) -> dict:
270
+ annotations = get_my_field_types(self)
271
+ result_dict = {}
272
+ for key, _ in annotations.items():
273
+ if not isinstance(key, str):
274
+ continue
275
+
276
+ if key.startswith("__"):
277
+ # ignore private attributes
278
+ continue
279
+
280
+ result_dict[key] = value_to_normal_obj(getattr(self, key))
281
+ return result_dict
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: trd_utils
3
- Version: 0.0.5
3
+ Version: 0.0.7
4
4
  Summary: Common Basic Utils for Python3. By ALiwoto.
5
5
  Keywords: utils,trd_utils,basic-utils,common-utils
6
6
  Author: ALiwoto
@@ -1,4 +1,4 @@
1
- trd_utils/__init__.py,sha256=r1FyIVMcj4G09lxuES6Tc50rbc-_eR52L74_l10QWJY,24
1
+ trd_utils/__init__.py,sha256=T3fa9wcYqXeAC8vAZ1EjWWLpXmx9tFj9SvTgGPKVr4Y,24
2
2
  trd_utils/cipher/__init__.py,sha256=V05KNuzQwCic-ihMVHlC8sENaJGc3I8MCb4pg4849X8,1765
3
3
  trd_utils/common_utils/float_utils.py,sha256=W-jv7nzjl88xwGB6gsEXmDDhF6DseOrrVT2qx7OvyCo,266
4
4
  trd_utils/exchanges/__init__.py,sha256=SQJt5cIXh305miWuDumkOLZHzqDUyOqSmlhTT9Xc9RY,180
@@ -15,9 +15,9 @@ trd_utils/html_utils/html_formats.py,sha256=unKsvOiiDmYTTaM0DYZEUNLEUzWQKKrqASJX
15
15
  trd_utils/tradingview/__init__.py,sha256=H0QYb-O5qvy7qC3yswtlcSWLmeBnaS6oJ3JtjvmaV_Y,154
16
16
  trd_utils/tradingview/tradingview_client.py,sha256=g_eWYaCRQAL8Kvd-r6AnAdbH7Jha6C_GAyCuxh-RQUU,3917
17
17
  trd_utils/tradingview/tradingview_types.py,sha256=z21MXPVdWHAduEl3gSeMIRhxtBN9yK-jPYHfZSMIbSA,6144
18
- trd_utils/types_helper/__init__.py,sha256=SB9_5bQkuxV059AKC4cXYwsLPT3lM4LOu2m8LpMhZlQ,60
19
- trd_utils/types_helper/base_model.py,sha256=08P5GatIjLoBGVudF7dcKDpibLqcpUeqE-zLRh1FjEE,5617
20
- trd_utils-0.0.5.dist-info/LICENSE,sha256=J1EP2xt87RjjmsTV1jTjHDQMLIM9FjdwEftTpw8hyv4,1067
21
- trd_utils-0.0.5.dist-info/METADATA,sha256=oD-HdWY6g30VIE623ZCBQf_8d0fcsMtXBcJVuEpotoc,1094
22
- trd_utils-0.0.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
23
- trd_utils-0.0.5.dist-info/RECORD,,
18
+ trd_utils/types_helper/__init__.py,sha256=VlEXDzOyn6fYH-dE86EGJ6u_el08QvdyOtJkj-0EAVA,65
19
+ trd_utils/types_helper/base_model.py,sha256=diowqH_nh21HDUki_0nbrEtZd8IxGCpwrN8yCVN8QDE,9311
20
+ trd_utils-0.0.7.dist-info/LICENSE,sha256=J1EP2xt87RjjmsTV1jTjHDQMLIM9FjdwEftTpw8hyv4,1067
21
+ trd_utils-0.0.7.dist-info/METADATA,sha256=Yy5-Rg6vMAN1W-ExlW6CJRa23Jzvebv9dvc0j4KEvNw,1094
22
+ trd_utils-0.0.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
23
+ trd_utils-0.0.7.dist-info/RECORD,,