stx-python 0.6.0__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.
- stx/__init__.py +61 -0
- stx/_async_client.py +923 -0
- stx/_base.py +64 -0
- stx/_client.py +502 -0
- stx/_config.py +107 -0
- stx/_http.py +131 -0
- stx/_money.py +122 -0
- stx/_operations.py +259 -0
- stx/_paging.py +59 -0
- stx/_results.py +29 -0
- stx/_retry.py +80 -0
- stx/_settings.py +203 -0
- stx/_signing.py +229 -0
- stx/_version.py +12 -0
- stx/_ws.py +1016 -0
- stx/enums.py +13 -0
- stx/exceptions.py +156 -0
- stx/models.py +2034 -0
- stx/py.typed +0 -0
- stx_python-0.6.0.dist-info/METADATA +121 -0
- stx_python-0.6.0.dist-info/RECORD +24 -0
- stx_python-0.6.0.dist-info/WHEEL +5 -0
- stx_python-0.6.0.dist-info/licenses/LICENSE +21 -0
- stx_python-0.6.0.dist-info/top_level.txt +1 -0
stx/enums.py
ADDED
stx/exceptions.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""Exceptions raised by the SDK.
|
|
2
|
+
|
|
3
|
+
REST errors arrive as ``{"error": "<message>"}`` with an HTTP status. The
|
|
4
|
+
status picks the exception class; the message is kept verbatim on
|
|
5
|
+
``.message`` (and ``str(exc)``), and the status on ``.status_code``.
|
|
6
|
+
|
|
7
|
+
======== =================================== =========================
|
|
8
|
+
Status Meaning Exception
|
|
9
|
+
======== =================================== =========================
|
|
10
|
+
400 Bad parameters STXValidationException
|
|
11
|
+
401 Missing or invalid signature STXAuthenticationException
|
|
12
|
+
403 Read-only key or account state STXForbiddenException
|
|
13
|
+
404 Not found, or not yours STXNotFoundException
|
|
14
|
+
422 Rejected by the exchange STXRejectedException
|
|
15
|
+
429 Rate limited STXRateLimitException
|
|
16
|
+
5xx Server error STXServerException
|
|
17
|
+
======== =================================== =========================
|
|
18
|
+
|
|
19
|
+
Network failures (connection refused, timeouts, TLS) raise
|
|
20
|
+
``STXTransportException``. Socket-level problems (a join the server
|
|
21
|
+
refused, a channel reply with ``status: error``) raise
|
|
22
|
+
``STXChannelException``.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from typing import Any, Optional
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class STXException(Exception):
|
|
31
|
+
"""Base for every error the SDK raises."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
message: str,
|
|
36
|
+
*,
|
|
37
|
+
status_code: Optional[int] = None,
|
|
38
|
+
body: Any = None,
|
|
39
|
+
method: Optional[str] = None,
|
|
40
|
+
path: Optional[str] = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
super().__init__(message)
|
|
43
|
+
self.message = message
|
|
44
|
+
self.status_code = status_code
|
|
45
|
+
self.body = body
|
|
46
|
+
self.method = method
|
|
47
|
+
self.path = path
|
|
48
|
+
|
|
49
|
+
def __str__(self) -> str:
|
|
50
|
+
return self.message
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class STXConfigException(STXException):
|
|
54
|
+
"""The client is misconfigured: unknown region, missing key, bad PEM."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class STXAPIException(STXException):
|
|
58
|
+
"""The API answered with an error status. Base for the classes below."""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class STXValidationException(STXAPIException):
|
|
62
|
+
"""400: a parameter or body field was rejected, e.g. ``price is required``."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class STXAuthenticationException(STXAPIException):
|
|
66
|
+
"""401: the signature, key id or timestamp was not accepted.
|
|
67
|
+
|
|
68
|
+
A machine clock more than 30 seconds off also lands here.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class STXForbiddenException(STXAPIException):
|
|
73
|
+
"""403: the key is read-only, or the account may not do this."""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class STXNotFoundException(STXAPIException):
|
|
77
|
+
"""404: the resource does not exist, or belongs to another account."""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class STXRejectedException(STXAPIException):
|
|
81
|
+
"""422: the exchange refused the request, e.g. insufficient funds or a
|
|
82
|
+
closed market."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class STXRateLimitException(STXAPIException):
|
|
86
|
+
"""429: too many requests. ``retry_after`` is seconds, when sent."""
|
|
87
|
+
|
|
88
|
+
def __init__(self, message: str, *, retry_after: Optional[float] = None, **kwargs: Any):
|
|
89
|
+
super().__init__(message, **kwargs)
|
|
90
|
+
self.retry_after = retry_after
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class STXServerException(STXAPIException):
|
|
94
|
+
"""5xx: the server failed. Retried by the default policy."""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class STXTransportException(STXException):
|
|
98
|
+
"""The request never got an answer: connection, DNS, TLS or timeout."""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class STXChannelException(STXException):
|
|
102
|
+
"""A channel join or channel message was refused by the server.
|
|
103
|
+
|
|
104
|
+
``reply`` holds the server's ``response`` object, for example
|
|
105
|
+
``{"reason": "unauthorized"}``.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def __init__(self, message: str, *, topic: str = "", reply: Any = None) -> None:
|
|
109
|
+
super().__init__(message)
|
|
110
|
+
self.topic = topic
|
|
111
|
+
self.reply = reply
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
_STATUS_MAP = {
|
|
115
|
+
400: STXValidationException,
|
|
116
|
+
401: STXAuthenticationException,
|
|
117
|
+
403: STXForbiddenException,
|
|
118
|
+
404: STXNotFoundException,
|
|
119
|
+
422: STXRejectedException,
|
|
120
|
+
429: STXRateLimitException,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def error_for_status(
|
|
125
|
+
status_code: int,
|
|
126
|
+
body: Any,
|
|
127
|
+
*,
|
|
128
|
+
method: str,
|
|
129
|
+
path: str,
|
|
130
|
+
retry_after: Optional[str] = None,
|
|
131
|
+
) -> STXAPIException:
|
|
132
|
+
"""Build the exception for one non-2xx response."""
|
|
133
|
+
# Message: the API's ``error`` string when the body has one, else the
|
|
134
|
+
# body text itself, else the status line.
|
|
135
|
+
if isinstance(body, dict) and isinstance(body.get("error"), str):
|
|
136
|
+
message = body["error"]
|
|
137
|
+
elif isinstance(body, str) and body.strip():
|
|
138
|
+
message = body.strip()[:500]
|
|
139
|
+
else:
|
|
140
|
+
message = f"HTTP {status_code}"
|
|
141
|
+
kwargs = {"status_code": status_code, "body": body, "method": method, "path": path}
|
|
142
|
+
if status_code == 429:
|
|
143
|
+
return STXRateLimitException(message, retry_after=_parse_retry_after(retry_after), **kwargs)
|
|
144
|
+
cls = _STATUS_MAP.get(status_code)
|
|
145
|
+
if cls is None:
|
|
146
|
+
cls = STXServerException if status_code >= 500 else STXAPIException
|
|
147
|
+
return cls(message, **kwargs)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _parse_retry_after(value: Optional[str]) -> Optional[float]:
|
|
151
|
+
if value is None:
|
|
152
|
+
return None
|
|
153
|
+
try:
|
|
154
|
+
return max(0.0, float(value))
|
|
155
|
+
except ValueError:
|
|
156
|
+
return None
|