unicex 0.1.14__tar.gz → 0.1.16__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 (72) hide show
  1. {unicex-0.1.14/unicex.egg-info → unicex-0.1.16}/PKG-INFO +1 -1
  2. {unicex-0.1.14 → unicex-0.1.16}/pyproject.toml +1 -1
  3. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/asyncio/client.py +38 -6
  4. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/asyncio/websocket.py +6 -1
  5. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/sync/client.py +38 -21
  6. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/_mixins/client.py +1 -0
  7. unicex-0.1.16/unicex/exceptions.py +64 -0
  8. {unicex-0.1.14 → unicex-0.1.16/unicex.egg-info}/PKG-INFO +1 -1
  9. unicex-0.1.14/unicex/exceptions.py +0 -39
  10. {unicex-0.1.14 → unicex-0.1.16}/LICENSE +0 -0
  11. {unicex-0.1.14 → unicex-0.1.16}/README.md +0 -0
  12. {unicex-0.1.14 → unicex-0.1.16}/setup.cfg +0 -0
  13. {unicex-0.1.14 → unicex-0.1.16}/unicex/__init__.py +0 -0
  14. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/__init__.py +0 -0
  15. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/adapter.py +0 -0
  16. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/asyncio/__init__.py +0 -0
  17. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/asyncio/uni_client.py +0 -0
  18. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/asyncio/uni_websocket_manager.py +0 -0
  19. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/sync/__init__.py +0 -0
  20. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/sync/uni_client.py +0 -0
  21. {unicex-0.1.14 → unicex-0.1.16}/unicex/_abc/sync/uni_websocket_manager.py +0 -0
  22. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/__init__.py +0 -0
  23. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/asyncio/__init__.py +0 -0
  24. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/sync/__init__.py +0 -0
  25. {unicex-0.1.14 → unicex-0.1.16}/unicex/_base/sync/websocket.py +0 -0
  26. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/__init__.py +0 -0
  27. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/_mixins/__init__.py +0 -0
  28. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/_mixins/client.py +0 -0
  29. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/_mixins/user_websocket.py +0 -0
  30. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/_mixins/websocket_manager.py +0 -0
  31. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/adapter.py +0 -0
  32. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/asyncio/__init__.py +0 -0
  33. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/asyncio/client.py +0 -0
  34. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/asyncio/uni_client.py +0 -0
  35. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/asyncio/uni_websocket_manager.py +0 -0
  36. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/asyncio/user_websocket.py +0 -0
  37. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/asyncio/websocket_manager.py +0 -0
  38. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/sync/__init__.py +0 -0
  39. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/sync/client.py +0 -0
  40. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/sync/uni_client.py +0 -0
  41. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/sync/uni_websocket_manager.py +0 -0
  42. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/sync/user_websocket.py +0 -0
  43. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/sync/websocket_manager.py +0 -0
  44. {unicex-0.1.14 → unicex-0.1.16}/unicex/binance/types.py +0 -0
  45. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/__init__.py +0 -0
  46. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/_mixins/__init__.py +0 -0
  47. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/_mixins/user_websocket.py +0 -0
  48. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/_mixins/websocket_manager.py +0 -0
  49. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/adapter.py +0 -0
  50. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/asyncio/__init__.py +0 -0
  51. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/asyncio/client.py +0 -0
  52. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/asyncio/uni_client.py +0 -0
  53. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/asyncio/uni_websocket_manager.py +0 -0
  54. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/asyncio/websocket_manager.py +0 -0
  55. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/sync/__init__.py +0 -0
  56. {unicex-0.1.14 → unicex-0.1.16}/unicex/bitget/types.py +0 -0
  57. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/__init__.py +0 -0
  58. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/adapter.py +0 -0
  59. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/client.py +0 -0
  60. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/types.py +0 -0
  61. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/uni_client.py +0 -0
  62. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/websocket.py +0 -0
  63. {unicex-0.1.14 → unicex-0.1.16}/unicex/bybit/websocket_manager.py +0 -0
  64. {unicex-0.1.14 → unicex-0.1.16}/unicex/enums.py +0 -0
  65. {unicex-0.1.14 → unicex-0.1.16}/unicex/extra.py +0 -0
  66. {unicex-0.1.14 → unicex-0.1.16}/unicex/mapper.py +0 -0
  67. {unicex-0.1.14 → unicex-0.1.16}/unicex/types.py +0 -0
  68. {unicex-0.1.14 → unicex-0.1.16}/unicex/utils.py +0 -0
  69. {unicex-0.1.14 → unicex-0.1.16}/unicex.egg-info/SOURCES.txt +0 -0
  70. {unicex-0.1.14 → unicex-0.1.16}/unicex.egg-info/dependency_links.txt +0 -0
  71. {unicex-0.1.14 → unicex-0.1.16}/unicex.egg-info/requires.txt +0 -0
  72. {unicex-0.1.14 → unicex-0.1.16}/unicex.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unicex
3
- Version: 0.1.14
3
+ Version: 0.1.16
4
4
  Summary: Unified Crypto Exchange API
5
5
  Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
6
6
  License: BSD 3-Clause License
@@ -4,7 +4,7 @@ name = "unicex"
4
4
  # • PATCH (x.y.Z) → увеличивается при багфиксе, который не ломает совместимость.
5
5
  # • MINOR (x.Y.z) → увеличивается при добавлении новой функциональности, но без ломающих изменений (backward-compatible).
6
6
  # • MAJOR (X.y.z) → увеличивается при изменениях, которые ломают обратную совместимость.
7
- version = "0.1.14"
7
+ version = "0.1.16"
8
8
 
9
9
  description = "Unified Crypto Exchange API "
10
10
  readme = "README.md"
@@ -1,12 +1,14 @@
1
1
  __all__ = ["BaseClient"]
2
2
 
3
3
  import asyncio
4
+ import json
4
5
  from itertools import cycle
5
6
  from typing import Any, Self
6
7
 
7
8
  import aiohttp
8
9
  from loguru import logger as _logger
9
10
 
11
+ from unicex.exceptions import ResponseError
10
12
  from unicex.types import LoggerLike, RequestMethod
11
13
 
12
14
 
@@ -168,15 +170,45 @@ class BaseClient:
168
170
  Возвращает:
169
171
  `dict | list`: Ответ API в формате JSON.
170
172
  """
171
- response.raise_for_status()
172
- result = await response.json()
173
+ response_text = await response.text()
174
+ status_code = response.status
173
175
 
176
+ # Парсинг JSON
177
+ try:
178
+ response_json = json.loads(response_text)
179
+ except json.JSONDecodeError as e:
180
+ raise ResponseError(
181
+ f"JSONDecodeError: {e}. Response: {response_text}. Status code: {response.status}",
182
+ status_code=status_code,
183
+ response_text=response_text,
184
+ ) from None
185
+
186
+ # Проверка HTTP-статуса
187
+ try:
188
+ response.raise_for_status()
189
+ except Exception as e:
190
+ error_code = next(
191
+ (
192
+ response_json[k]
193
+ for k in ("code", "err_code", "errCode", "status")
194
+ if k in response_json
195
+ ),
196
+ "",
197
+ )
198
+ raise ResponseError(
199
+ f"HTTP error: {e}. Response: {response_json}. Status code: {response.status}",
200
+ status_code=status_code,
201
+ code=error_code,
202
+ response_text=response_text,
203
+ response_json=response_json,
204
+ ) from None
205
+
206
+ # Логирование ответа
174
207
  try:
175
- result_str: str = str(result)
176
208
  self._logger.debug(
177
- f"Response: {result_str[:100]} {'...' if len(result_str) > 100 else ''}"
209
+ f"Response: {response_text[:300]}{'...' if len(response_text) > 300 else ''}"
178
210
  )
179
211
  except Exception as e:
180
- self._logger.error(f"Error while log response: {e}")
212
+ self._logger.error(f"Error while logging response: {e}")
181
213
 
182
- return result
214
+ return response_json
@@ -71,7 +71,12 @@ class Websocket:
71
71
  self._running = True
72
72
 
73
73
  # Запускаем вебсокет
74
- await self._connect()
74
+ try:
75
+ await self._connect()
76
+ except Exception as e:
77
+ self._logger.error(f"Failed to connect to websocket: {e}")
78
+ self._running = False
79
+ raise
75
80
 
76
81
  async def stop(self) -> None:
77
82
  """Останавливает вебсокет и рабочие задачи."""
@@ -1,5 +1,6 @@
1
1
  __all__ = ["BaseClient"]
2
2
 
3
+ import json
3
4
  import time
4
5
  from itertools import cycle
5
6
  from typing import Any, Self
@@ -7,7 +8,7 @@ from typing import Any, Self
7
8
  import requests
8
9
  from loguru import logger as _logger
9
10
 
10
- from unicex.exceptions import UniCexException
11
+ from unicex.exceptions import ResponseError
11
12
  from unicex.types import LoggerLike, RequestMethod
12
13
 
13
14
 
@@ -133,37 +134,53 @@ class BaseClient:
133
134
  ) from errors[-1]
134
135
 
135
136
  def _handle_response(self, response: requests.Response) -> Any:
136
- """Обрабатывает HTTP‑ответ.
137
+ """Обрабатывает HTTP-ответ.
137
138
 
138
139
  Параметры:
139
- response (`requests.Response`): Ответ HTTP‑запроса.
140
+ response (`requests.Response`): Ответ HTTP-запроса.
140
141
 
141
142
  Возвращает:
142
143
  `dict | list`: Ответ API в формате JSON.
143
144
  """
145
+ response_text = response.text
146
+ status_code = response.status_code
147
+
148
+ # Парсинг JSON
149
+ try:
150
+ response_json = json.loads(response_text)
151
+ except json.JSONDecodeError as e:
152
+ raise ResponseError(
153
+ f"JSONDecodeError: {e}. Response: {response_text}. Status code: {status_code}",
154
+ status_code=status_code,
155
+ response_text=response_text,
156
+ ) from None
157
+
158
+ # Проверка HTTP-статуса
144
159
  try:
145
160
  response.raise_for_status()
146
161
  except Exception as e:
147
- raise UniCexException(
148
- f"HTTP error: {e}. Response: {response.text}. Status code: {response.status_code}"
149
- ) from e
150
-
151
- if not response.content:
152
- raise UniCexException(f"Empty response. Status code: {response.status_code}")
153
-
154
- try:
155
- result = response.json()
156
- except requests.exceptions.JSONDecodeError as e:
157
- raise UniCexException(
158
- f"JSONDecodeError error: {e}. Response: {response.text}. Status code: {response.status_code}"
159
- ) from e
160
-
162
+ error_code = next(
163
+ (
164
+ response_json[k]
165
+ for k in ("code", "err_code", "errCode", "status")
166
+ if k in response_json
167
+ ),
168
+ "",
169
+ )
170
+ raise ResponseError(
171
+ f"HTTP error: {e}. Response: {response_json}. Status code: {status_code}",
172
+ status_code=status_code,
173
+ code=error_code,
174
+ response_text=response_text,
175
+ response_json=response_json,
176
+ ) from None
177
+
178
+ # Логирование ответа
161
179
  try:
162
- result_str: str = str(result)
163
180
  self._logger.debug(
164
- f"Response: {result_str[:100]} {'...' if len(result_str) > 100 else ''}"
181
+ f"Response: {response_text[:300]}{'...' if len(response_text) > 300 else ''}"
165
182
  )
166
183
  except Exception as e:
167
- self._logger.error(f"Error while log response: {e}")
184
+ self._logger.error(f"Error while logging response: {e}")
168
185
 
169
- return result
186
+ return response_json
@@ -74,6 +74,7 @@ class ClientMixin:
74
74
  "ACCESS-PASSPHRASE": self._api_passphrase, # type: ignore[attr-defined]
75
75
  "ACCESS-TIMESTAMP": timestamp,
76
76
  "ACCESS-SIGN": signature,
77
+ "locale": "en-US",
77
78
  }
78
79
  )
79
80
  return headers
@@ -0,0 +1,64 @@
1
+ """Модуль,который описывает исключения и ошибки, которые могут возникнуть при работе с библиотекой."""
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+
6
+ @dataclass
7
+ class UniCexException(Exception):
8
+ """Базовое исключение библиотеки."""
9
+
10
+ message: str
11
+ """Сообщение об ошибке."""
12
+
13
+
14
+ @dataclass
15
+ class NotAuthorized(UniCexException):
16
+ """Исключение, возникающее при отсутствии авторизации."""
17
+
18
+ pass
19
+
20
+
21
+ @dataclass
22
+ class NotSupported(UniCexException):
23
+ """Исключение, возникающее при попытке использования не поддерживаемой функции."""
24
+
25
+ pass
26
+
27
+
28
+ @dataclass
29
+ class AdapterError(UniCexException):
30
+ """Исключение, возникающее при ошибке адаптации данных."""
31
+
32
+ pass
33
+
34
+
35
+ @dataclass
36
+ class QueueOverflowError(UniCexException):
37
+ """Исключение, возникающее при переполнении очереди сообщений."""
38
+
39
+ pass
40
+
41
+
42
+ @dataclass
43
+ class ResponseError(UniCexException):
44
+ """Исключение, возникающее при ошибке ответа."""
45
+
46
+ status_code: int
47
+ code: str = "" # "" - means undefined
48
+ response_json: dict = field(default_factory=dict)
49
+ response_text: str = ""
50
+
51
+ def __str__(self) -> str:
52
+ """Возвращает строковое представление исключения."""
53
+ if self.response_json:
54
+ preview = str(self.response_json)
55
+ if len(preview) > 500:
56
+ preview = preview[:500] + "..."
57
+ return f"ResponseError: status_code={self.status_code}, code={self.code}, response_json: {preview}"
58
+ elif self.response_text:
59
+ preview = str(self.response_text)
60
+ if len(preview) > 500:
61
+ preview = preview[:500] + "..."
62
+ return f"ResponseError: status_code={self.status_code}, code={self.code}, response_text: {preview}"
63
+ else:
64
+ return f"ResponseError: status_code={self.status_code}, code={self.code}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unicex
3
- Version: 0.1.14
3
+ Version: 0.1.16
4
4
  Summary: Unified Crypto Exchange API
5
5
  Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
6
6
  License: BSD 3-Clause License
@@ -1,39 +0,0 @@
1
- """Модуль,который описывает исключения и ошибки, которые могут возникнуть при работе с библиотекой."""
2
-
3
- from dataclasses import dataclass
4
-
5
-
6
- @dataclass
7
- class UniCexException(Exception):
8
- """Базовое исключение библиотеки."""
9
-
10
- message: str
11
- """Сообщение об ошибке."""
12
-
13
-
14
- @dataclass
15
- class NotAuthorized(UniCexException):
16
- """Исключение, возникающее при отсутствии авторизации."""
17
-
18
- pass
19
-
20
-
21
- @dataclass
22
- class NotSupported(UniCexException):
23
- """Исключение, возникающее при попытке использования не поддерживаемой функции."""
24
-
25
- pass
26
-
27
-
28
- @dataclass
29
- class AdapterError(UniCexException):
30
- """Исключение, возникающее при ошибке адаптации данных."""
31
-
32
- pass
33
-
34
-
35
- @dataclass
36
- class QueueOverflowError(UniCexException):
37
- """Исключение, возникающее при переполнении очереди сообщений."""
38
-
39
- pass
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes