trd-utils 0.0.5__tar.gz → 0.0.7__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 trd-utils might be problematic. Click here for more details.

Files changed (25) hide show
  1. {trd_utils-0.0.5 → trd_utils-0.0.7}/PKG-INFO +1 -1
  2. {trd_utils-0.0.5 → trd_utils-0.0.7}/pyproject.toml +1 -1
  3. trd_utils-0.0.7/trd_utils/__init__.py +3 -0
  4. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/types_helper/__init__.py +3 -1
  5. trd_utils-0.0.7/trd_utils/types_helper/base_model.py +281 -0
  6. trd_utils-0.0.5/trd_utils/__init__.py +0 -3
  7. trd_utils-0.0.5/trd_utils/types_helper/base_model.py +0 -149
  8. {trd_utils-0.0.5 → trd_utils-0.0.7}/LICENSE +0 -0
  9. {trd_utils-0.0.5 → trd_utils-0.0.7}/README.md +0 -0
  10. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/cipher/__init__.py +0 -0
  11. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/common_utils/float_utils.py +0 -0
  12. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/__init__.py +0 -0
  13. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/blofin/__init__.py +0 -0
  14. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/blofin/blofin_client.py +0 -0
  15. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/blofin/blofin_types.py +0 -0
  16. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/bx_ultra/__init__.py +0 -0
  17. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/bx_ultra/bx_types.py +0 -0
  18. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/bx_ultra/bx_ultra_client.py +0 -0
  19. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/bx_ultra/bx_utils.py +0 -0
  20. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/exchanges/exchange_base.py +0 -0
  21. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/html_utils/__init__.py +0 -0
  22. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/html_utils/html_formats.py +0 -0
  23. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/tradingview/__init__.py +0 -0
  24. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/tradingview/tradingview_client.py +0 -0
  25. {trd_utils-0.0.5 → trd_utils-0.0.7}/trd_utils/tradingview/tradingview_types.py +0 -0
@@ -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,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "trd_utils"
3
- version = "0.0.5"
3
+ version = "0.0.7"
4
4
  description = "Common Basic Utils for Python3. By ALiwoto."
5
5
  authors = ["ALiwoto <aminnimaj@gmail.com>"]
6
6
  packages = [
@@ -0,0 +1,3 @@
1
+
2
+ __version__ = "0.0.7"
3
+
@@ -1,4 +1,6 @@
1
1
  from .base_model import BaseModel
2
2
 
3
3
 
4
- __all__ = ["BaseModel"]
4
+ __all__ = [
5
+ BaseModel,
6
+ ]
@@ -0,0 +1,281 @@
1
+ from decimal import Decimal
2
+ import json
3
+ from typing import (
4
+ Union,
5
+ get_type_hints,
6
+ Any,
7
+ get_args as get_type_args,
8
+ )
9
+
10
+ from trd_utils.html_utils.html_formats import camel_to_snake
11
+
12
+ # Whether to use ultra-list instead of normal python list or not.
13
+ # This might be convenient in some cases, but it is not recommended
14
+ # to use it in production code because of the performance overhead.
15
+ ULTRA_LIST_ENABLED: bool = False
16
+
17
+ # Whether to also set the camelCase attribute names for the model.
18
+ # This is useful when the API returns camelCase attribute names
19
+ # and you want to use them as is in the model; by default, the
20
+ # attribute names are converted to snake_case.
21
+ SET_CAMEL_ATTR_NAMES = False
22
+
23
+
24
+ def get_my_field_types(cls):
25
+ type_hints = {}
26
+ for current_cls in cls.__class__.__mro__:
27
+ if current_cls is object or current_cls is BaseModel:
28
+ break
29
+ type_hints.update(get_type_hints(current_cls))
30
+ return type_hints
31
+
32
+
33
+ def get_real_attr(cls, attr_name):
34
+ if cls is None:
35
+ return None
36
+
37
+ if isinstance(cls, dict):
38
+ return cls.get(attr_name, None)
39
+
40
+ if hasattr(cls, attr_name):
41
+ return getattr(cls, attr_name)
42
+
43
+ return None
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
+
129
+ class UltraList(list):
130
+ def __getattr__(self, attr):
131
+ if len(self) == 0:
132
+ return None
133
+ return UltraList([get_real_attr(item, attr) for item in self])
134
+
135
+
136
+ def convert_to_ultra_list(value: Any) -> UltraList:
137
+ if not value:
138
+ return UltraList()
139
+
140
+ # Go through all fields of the value and convert them to
141
+ # UltraList if they are lists
142
+
143
+ try:
144
+ if isinstance(value, list):
145
+ return UltraList([convert_to_ultra_list(item) for item in value])
146
+ elif isinstance(value, dict):
147
+ return {k: convert_to_ultra_list(v) for k, v in value.items()}
148
+ elif isinstance(value, tuple):
149
+ return tuple(convert_to_ultra_list(v) for v in value)
150
+ elif isinstance(value, set):
151
+ return {convert_to_ultra_list(v) for v in value}
152
+
153
+ for attr, attr_value in get_my_field_types(value).items():
154
+ if isinstance(attr_value, list):
155
+ setattr(value, attr, convert_to_ultra_list(getattr(value, attr)))
156
+
157
+ return value
158
+ except Exception:
159
+ return value
160
+
161
+
162
+ class BaseModel:
163
+ def __init__(self, **kwargs):
164
+ annotations = get_my_field_types(self)
165
+ # annotations = self.__annotations__
166
+ for key, value in kwargs.items():
167
+ corrected_key = key
168
+ if key not in annotations:
169
+ # key does not exist, try converting it to snake_case
170
+ corrected_key = camel_to_snake(key)
171
+ if corrected_key not in annotations:
172
+ # just ignore and continue
173
+ annotations[key] = Any
174
+ annotations[corrected_key] = Any
175
+
176
+ expected_type = annotations[corrected_key]
177
+ if hasattr(self, "_get_" + corrected_key + "_type"):
178
+ try:
179
+ overridden_type = getattr(self, "_get_" + corrected_key + "_type")(
180
+ kwargs
181
+ )
182
+ if overridden_type:
183
+ expected_type = overridden_type
184
+ except Exception:
185
+ pass
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"
191
+ # maybe in the future we can have some other usages for is_optional_type
192
+ # variable or something like that.
193
+ if is_optional_type:
194
+ try:
195
+ expected_type = expected_type_args[0]
196
+ except Exception:
197
+ # something went wrong, just ignore and continue
198
+ expected_type = Any
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
+
210
+ # Handle nested models
211
+ elif isinstance(value, dict) and issubclass(expected_type, BaseModel):
212
+ value = expected_type(**value)
213
+
214
+ elif isinstance(value, list):
215
+ if not expected_type_args:
216
+ # if it's Any, it means we shouldn't really care about the type
217
+ if expected_type != Any:
218
+ value = expected_type(value)
219
+ else:
220
+ value = generic_obj_to_value(
221
+ expected_type=expected_type,
222
+ expected_type_args=expected_type_args,
223
+ value=value,
224
+ )
225
+
226
+ if ULTRA_LIST_ENABLED and isinstance(value, list):
227
+ value = convert_to_ultra_list(value)
228
+
229
+ # Type checking
230
+ elif not (is_any_type(expected_type) or isinstance(value, expected_type)):
231
+ try:
232
+ value = expected_type(value)
233
+ except Exception:
234
+ raise TypeError(
235
+ f"Field {corrected_key} must be of type {expected_type},"
236
+ + f" but it's {type(value)}"
237
+ )
238
+
239
+ setattr(self, corrected_key, value)
240
+ if SET_CAMEL_ATTR_NAMES and key != corrected_key:
241
+ setattr(self, key, value)
242
+
243
+ # Check if all required fields are present
244
+ # for field in self.__annotations__:
245
+ # if not hasattr(self, field):
246
+ # raise ValueError(f"Missing required field: {field}")
247
+
248
+ @classmethod
249
+ def deserialize(cls, json_data: Union[str, dict]):
250
+ if isinstance(json_data, str):
251
+ data = json.loads(json_data)
252
+ else:
253
+ data = json_data
254
+ return cls(**data)
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,3 +0,0 @@
1
-
2
- __version__ = "0.0.5"
3
-
@@ -1,149 +0,0 @@
1
- import json
2
- from typing import (
3
- Union,
4
- get_type_hints,
5
- Any,
6
- get_args as get_type_args
7
- )
8
-
9
- from trd_utils.html_utils.html_formats import camel_to_snake
10
-
11
- # Whether to use ultra-list instead of normal python list or not.
12
- # This might be convenient in some cases, but it is not recommended
13
- # to use it in production code because of the performance overhead.
14
- ULTRA_LIST_ENABLED: bool = False
15
-
16
- # Whether to also set the camelCase attribute names for the model.
17
- # This is useful when the API returns camelCase attribute names
18
- # and you want to use them as is in the model; by default, the
19
- # attribute names are converted to snake_case.
20
- SET_CAMEL_ATTR_NAMES = False
21
-
22
- def get_my_field_types(cls):
23
- type_hints = {}
24
- for current_cls in cls.__class__.__mro__:
25
- if current_cls is object or current_cls is BaseModel:
26
- break
27
- type_hints.update(get_type_hints(current_cls))
28
- return type_hints
29
-
30
- def get_real_attr(cls, attr_name):
31
- if cls is None:
32
- return None
33
-
34
- if isinstance(cls, dict):
35
- return cls.get(attr_name, None)
36
-
37
- if hasattr(cls, attr_name):
38
- return getattr(cls, attr_name)
39
-
40
- return None
41
-
42
- class UltraList(list):
43
- def __getattr__(self, attr):
44
- if len(self) == 0:
45
- return None
46
- return UltraList([get_real_attr(item, attr) for item in self])
47
-
48
- def convert_to_ultra_list(value: Any) -> UltraList:
49
- if not value:
50
- return UltraList()
51
-
52
- # Go through all fields of the value and convert them to
53
- # UltraList if they are lists
54
-
55
- try:
56
- if isinstance(value, list):
57
- return UltraList([convert_to_ultra_list(item) for item in value])
58
- elif isinstance(value, dict):
59
- return {k: convert_to_ultra_list(v) for k, v in value.items()}
60
- elif isinstance(value, tuple):
61
- return tuple(convert_to_ultra_list(v) for v in value)
62
- elif isinstance(value, set):
63
- return {convert_to_ultra_list(v) for v in value}
64
-
65
- for attr, attr_value in get_my_field_types(value).items():
66
- if isinstance(attr_value, list):
67
- setattr(value, attr, convert_to_ultra_list(getattr(value, attr)))
68
-
69
- return value
70
- except Exception:
71
- return value
72
-
73
- class BaseModel:
74
- def __init__(self, **kwargs):
75
- annotations = get_my_field_types(self)
76
- # annotations = self.__annotations__
77
- for key, value in kwargs.items():
78
- corrected_key = key
79
- if key not in annotations:
80
- # key does not exist, try converting it to snake_case
81
- corrected_key = camel_to_snake(key)
82
- if corrected_key not in annotations:
83
- # just ignore and continue
84
- annotations[key] = Any
85
- annotations[corrected_key] = Any
86
-
87
- expected_type = annotations[corrected_key]
88
- if hasattr(self, "_get_" + corrected_key + "_type"):
89
- try:
90
- overridden_type = getattr(self, "_get_" + corrected_key + "_type")(kwargs)
91
- if overridden_type:
92
- expected_type = overridden_type
93
- except Exception:
94
- pass
95
-
96
- is_optional_type = getattr(expected_type, '_name', None) == 'Optional'
97
- # maybe in the future we can have some other usages for is_optional_type
98
- # variable or something like that.
99
- if is_optional_type:
100
- try:
101
- expected_type = get_type_args(expected_type)[0]
102
- except Exception:
103
- # something went wrong, just ignore and continue
104
- expected_type = Any
105
-
106
- # Handle nested models
107
- if isinstance(value, dict) and issubclass(expected_type, BaseModel):
108
- value = expected_type(**value)
109
-
110
- elif isinstance(value, list):
111
- type_args = get_type_args(expected_type)
112
- if not type_args:
113
- # if it's Any, it means we shouldn't really care about the type
114
- if expected_type != Any:
115
- value = expected_type(value)
116
- 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
-
122
- if ULTRA_LIST_ENABLED and isinstance(value, list):
123
- value = convert_to_ultra_list(value)
124
-
125
- # Type checking
126
- elif expected_type != Any and not isinstance(value, expected_type):
127
- try:
128
- value = expected_type(value)
129
- except Exception:
130
- raise TypeError(f"Field {corrected_key} must be of type {expected_type}," +
131
- f" but it's {type(value)}")
132
-
133
- setattr(self, corrected_key, value)
134
- if SET_CAMEL_ATTR_NAMES and key != corrected_key:
135
- setattr(self, key, value)
136
-
137
- # Check if all required fields are present
138
- # for field in self.__annotations__:
139
- # if not hasattr(self, field):
140
- # raise ValueError(f"Missing required field: {field}")
141
-
142
- @classmethod
143
- def deserialize(cls, json_data: Union[str, dict]):
144
- if isinstance(json_data, str):
145
- data = json.loads(json_data)
146
- else:
147
- data = json_data
148
- return cls(**data)
149
-
File without changes
File without changes