crypticorn-utils 0.1.0rc1__tar.gz → 1.0.0rc1__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.
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/LICENSE +1 -1
- crypticorn_utils-1.0.0rc1/MANIFEST.in +4 -0
- {crypticorn_utils-0.1.0rc1/crypticorn_utils.egg-info → crypticorn_utils-1.0.0rc1}/PKG-INFO +20 -5
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/README.md +18 -0
- crypticorn_utils-1.0.0rc1/crypticorn_utils/__init__.py +50 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/_migration.py +2 -1
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/ansi_colors.py +1 -4
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/auth.py +112 -54
- crypticorn_utils-1.0.0rc1/crypticorn_utils/enums.py +55 -0
- crypticorn_utils-1.0.0rc1/crypticorn_utils/errors.py +25 -0
- crypticorn_utils-1.0.0rc1/crypticorn_utils/exceptions.py +288 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/logging.py +5 -19
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/metrics.py +1 -2
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/middleware.py +7 -40
- crypticorn_utils-1.0.0rc1/crypticorn_utils/utils.py +42 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/warnings.py +0 -28
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1/crypticorn_utils.egg-info}/PKG-INFO +20 -5
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/SOURCES.txt +2 -14
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/requires.txt +0 -1
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/pyproject.toml +15 -4
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/requirements/dev.txt +0 -1
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/requirements/main.txt +0 -2
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/tests/test_auth_client.py +27 -31
- crypticorn_utils-1.0.0rc1/tests/test_exceptions.py +456 -0
- crypticorn_utils-0.1.0rc1/MANIFEST.in +0 -3
- crypticorn_utils-0.1.0rc1/crypticorn_utils/__init__.py +0 -16
- crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/__init__.py +0 -4
- crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/__main__.py +0 -17
- crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/init.py +0 -127
- crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/templates/auth.py +0 -33
- crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/version.py +0 -8
- crypticorn_utils-0.1.0rc1/crypticorn_utils/enums.py +0 -175
- crypticorn_utils-0.1.0rc1/crypticorn_utils/errors.py +0 -915
- crypticorn_utils-0.1.0rc1/crypticorn_utils/exceptions.py +0 -183
- crypticorn_utils-0.1.0rc1/crypticorn_utils/mixins.py +0 -68
- crypticorn_utils-0.1.0rc1/crypticorn_utils/openapi.py +0 -10
- crypticorn_utils-0.1.0rc1/crypticorn_utils/router/admin_router.py +0 -117
- crypticorn_utils-0.1.0rc1/crypticorn_utils/router/status_router.py +0 -36
- crypticorn_utils-0.1.0rc1/crypticorn_utils/utils.py +0 -93
- crypticorn_utils-0.1.0rc1/tests/test_common_routers.py +0 -111
- crypticorn_utils-0.1.0rc1/tests/test_config.py +0 -22
- crypticorn_utils-0.1.0rc1/tests/test_enums.py +0 -44
- crypticorn_utils-0.1.0rc1/tests/test_errors.py +0 -63
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/decorators.py +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/pagination.py +0 -0
- crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/templates/__init__.py → crypticorn_utils-1.0.0rc1/crypticorn_utils/py.typed +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/dependency_links.txt +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/entry_points.txt +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/top_level.txt +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/requirements/test.txt +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/setup.cfg +0 -0
- {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/tests/test_pagination.py +7 -7
@@ -12,4 +12,4 @@ Changes to this agreement may be made without notice, and it is the user's respo
|
|
12
12
|
|
13
13
|
If any provision of this license agreement is held to be invalid or unenforceable under applicable law, the remaining provisions will continue in full force and effect. Crypticorn's failure to enforce any provision of this agreement does not constitute a waiver of its right to do so in the future.
|
14
14
|
|
15
|
-
This agreement is written in English. In the event of any discrepancy between the English version and any translation, the English version shall prevail.
|
15
|
+
This agreement is written in English. In the event of any discrepancy between the English version and any translation, the English version shall prevail.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: crypticorn_utils
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0rc1
|
4
4
|
Summary: Shared utilities for the Crypticorn APIs
|
5
5
|
Author-email: Crypticorn <timon@crypticorn.com>
|
6
6
|
License-Expression: MIT
|
@@ -11,20 +11,17 @@ Classifier: Topic :: Scientific/Engineering
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
12
12
|
Classifier: Intended Audience :: Developers
|
13
13
|
Classifier: Operating System :: OS Independent
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
16
14
|
Classifier: Programming Language :: Python :: 3.11
|
17
15
|
Classifier: Programming Language :: Python :: 3.12
|
18
16
|
Classifier: Programming Language :: Python :: 3.13
|
19
17
|
Classifier: Typing :: Typed
|
20
|
-
Requires-Python: >=3.
|
18
|
+
Requires-Python: >=3.11
|
21
19
|
Description-Content-Type: text/markdown
|
22
20
|
License-File: LICENSE
|
23
21
|
Requires-Dist: fastapi<1.0.0,>=0.115.0
|
24
22
|
Requires-Dist: click<9.0.0,>=8.0.0
|
25
23
|
Requires-Dist: psutil<8.0.0,>=7.0.0
|
26
24
|
Requires-Dist: setuptools<81.0.0,>=80.0.0
|
27
|
-
Requires-Dist: strenum
|
28
25
|
Requires-Dist: prometheus-client<1.0.0,>=0.22.0
|
29
26
|
Provides-Extra: dev
|
30
27
|
Requires-Dist: build; extra == "dev"
|
@@ -68,6 +65,24 @@ This module serves as a central place for providing utilities for our python bac
|
|
68
65
|
|
69
66
|
<!-- changelog-insertion -->
|
70
67
|
|
68
|
+
## v1.0.0-rc.1 (2025-07-17)
|
69
|
+
|
70
|
+
### Build System
|
71
|
+
|
72
|
+
- Deployment config for v1 branches
|
73
|
+
([`b94d9e7`](https://github.com/crypticorn-ai/util-libraries/commit/b94d9e72616e398760993f6ebb1a6fd876a95802))
|
74
|
+
|
75
|
+
BREAKING CHANGE: - removed: mixins, openapi and both router modules; CLI; Scope Enum class;
|
76
|
+
`throw_if_none` and `throw_if_falsy`; all deprecation warnings - reworked: exceptions and error
|
77
|
+
modules
|
78
|
+
|
79
|
+
- Mark packaage as typed
|
80
|
+
([`69544a8`](https://github.com/crypticorn-ai/util-libraries/commit/69544a8709f4d55850e107031b82d91c28334b3c))
|
81
|
+
|
82
|
+
- Remove support for python versions 3.9 and 3.10
|
83
|
+
([`80b8543`](https://github.com/crypticorn-ai/util-libraries/commit/80b8543ed5559a0de421aef4e2382193e930751a))
|
84
|
+
|
85
|
+
|
71
86
|
## v0.1.0-rc.1 (2025-06-23)
|
72
87
|
|
73
88
|
### Documentation
|
@@ -21,6 +21,24 @@ This module serves as a central place for providing utilities for our python bac
|
|
21
21
|
|
22
22
|
<!-- changelog-insertion -->
|
23
23
|
|
24
|
+
## v1.0.0-rc.1 (2025-07-17)
|
25
|
+
|
26
|
+
### Build System
|
27
|
+
|
28
|
+
- Deployment config for v1 branches
|
29
|
+
([`b94d9e7`](https://github.com/crypticorn-ai/util-libraries/commit/b94d9e72616e398760993f6ebb1a6fd876a95802))
|
30
|
+
|
31
|
+
BREAKING CHANGE: - removed: mixins, openapi and both router modules; CLI; Scope Enum class;
|
32
|
+
`throw_if_none` and `throw_if_falsy`; all deprecation warnings - reworked: exceptions and error
|
33
|
+
modules
|
34
|
+
|
35
|
+
- Mark packaage as typed
|
36
|
+
([`69544a8`](https://github.com/crypticorn-ai/util-libraries/commit/69544a8709f4d55850e107031b82d91c28334b3c))
|
37
|
+
|
38
|
+
- Remove support for python versions 3.9 and 3.10
|
39
|
+
([`80b8543`](https://github.com/crypticorn-ai/util-libraries/commit/80b8543ed5559a0de421aef4e2382193e930751a))
|
40
|
+
|
41
|
+
|
24
42
|
## v0.1.0-rc.1 (2025-06-23)
|
25
43
|
|
26
44
|
### Documentation
|
@@ -0,0 +1,50 @@
|
|
1
|
+
from crypticorn_utils.auth import AuthHandler
|
2
|
+
from crypticorn_utils.decorators import partial_model
|
3
|
+
from crypticorn_utils.enums import ApiEnv, BaseUrl, Exchange, MarketType
|
4
|
+
from crypticorn_utils.errors import ErrorLevel, ErrorType
|
5
|
+
from crypticorn_utils.exceptions import BaseError, ExceptionHandler, ExceptionType
|
6
|
+
from crypticorn_utils.logging import configure_logging, disable_logging
|
7
|
+
from crypticorn_utils.middleware import add_middleware
|
8
|
+
from crypticorn_utils.pagination import (
|
9
|
+
FilterParams,
|
10
|
+
HeavyPageSortFilterParams,
|
11
|
+
HeavyPaginationParams,
|
12
|
+
PageFilterParams,
|
13
|
+
PageSortFilterParams,
|
14
|
+
PageSortParams,
|
15
|
+
PaginatedResponse,
|
16
|
+
PaginationParams,
|
17
|
+
SortFilterParams,
|
18
|
+
SortParams,
|
19
|
+
)
|
20
|
+
from crypticorn_utils.utils import datetime_to_timestamp, gen_random_id, optional_import
|
21
|
+
|
22
|
+
__all__ = [
|
23
|
+
"AuthHandler",
|
24
|
+
"partial_model",
|
25
|
+
"Exchange",
|
26
|
+
"MarketType",
|
27
|
+
"ApiEnv",
|
28
|
+
"BaseUrl",
|
29
|
+
"ErrorType",
|
30
|
+
"ErrorLevel",
|
31
|
+
"BaseError",
|
32
|
+
"ExceptionHandler",
|
33
|
+
"ExceptionType",
|
34
|
+
"configure_logging",
|
35
|
+
"disable_logging",
|
36
|
+
"add_middleware",
|
37
|
+
"PaginatedResponse",
|
38
|
+
"PaginationParams",
|
39
|
+
"HeavyPaginationParams",
|
40
|
+
"SortParams",
|
41
|
+
"FilterParams",
|
42
|
+
"SortFilterParams",
|
43
|
+
"PageFilterParams",
|
44
|
+
"PageSortParams",
|
45
|
+
"PageSortFilterParams",
|
46
|
+
"HeavyPageSortFilterParams",
|
47
|
+
"gen_random_id",
|
48
|
+
"datetime_to_timestamp",
|
49
|
+
"optional_import",
|
50
|
+
]
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# This file is used to check if the crypticorn version is greater than 2.18
|
2
2
|
# This is to be compatible with this new utils library
|
3
|
+
# otherwise prometheus reqisters metrics twice, resulting in an exception
|
3
4
|
|
4
5
|
import importlib.metadata
|
5
6
|
from importlib.metadata import PackageNotFoundError
|
@@ -9,4 +10,4 @@ try:
|
|
9
10
|
parts = crypticorn_version.split(".")
|
10
11
|
has_migrated = parts[0] >= "2" and parts[1] > "18"
|
11
12
|
except PackageNotFoundError:
|
12
|
-
has_migrated =
|
13
|
+
has_migrated = True
|
@@ -1,11 +1,17 @@
|
|
1
1
|
import json
|
2
|
+
from enum import StrEnum
|
2
3
|
from typing import Union
|
3
4
|
|
4
5
|
from crypticorn.auth import AuthClient, Configuration, Verify200Response
|
5
6
|
from crypticorn.auth.client.exceptions import ApiException
|
6
|
-
from crypticorn_utils.enums import
|
7
|
-
from crypticorn_utils.exceptions import
|
8
|
-
|
7
|
+
from crypticorn_utils.enums import BaseUrl
|
8
|
+
from crypticorn_utils.exceptions import (
|
9
|
+
BaseError,
|
10
|
+
ErrorLevel,
|
11
|
+
ErrorType,
|
12
|
+
ExceptionHandler,
|
13
|
+
)
|
14
|
+
from fastapi import Depends, HTTPException, Query, status
|
9
15
|
from fastapi.security import (
|
10
16
|
APIKeyHeader,
|
11
17
|
HTTPAuthorizationCredentials,
|
@@ -16,6 +22,79 @@ from fastapi.security import (
|
|
16
22
|
)
|
17
23
|
from typing_extensions import Annotated
|
18
24
|
|
25
|
+
|
26
|
+
class AuthErrorCodes(StrEnum):
|
27
|
+
INVALID_API_KEY = "invalid_api_key"
|
28
|
+
EXPIRED_API_KEY = "expired_api_key"
|
29
|
+
INVALID_BEARER = "invalid_bearer"
|
30
|
+
EXPIRED_BEARER = "expired_bearer"
|
31
|
+
INVALID_BASIC_AUTH = "invalid_basic_auth"
|
32
|
+
NO_CREDENTIALS = "no_credentials"
|
33
|
+
INSUFFICIENT_SCOPES = "insufficient_scopes"
|
34
|
+
UNKNOWN_ERROR = "unknown_error"
|
35
|
+
|
36
|
+
|
37
|
+
class AuthError(BaseError):
|
38
|
+
INVALID_API_KEY = (
|
39
|
+
AuthErrorCodes.INVALID_API_KEY,
|
40
|
+
ErrorType.USER_ERROR,
|
41
|
+
ErrorLevel.ERROR,
|
42
|
+
status.HTTP_401_UNAUTHORIZED,
|
43
|
+
status.WS_1008_POLICY_VIOLATION,
|
44
|
+
)
|
45
|
+
INVALID_BASIC_AUTH = (
|
46
|
+
AuthErrorCodes.INVALID_BASIC_AUTH,
|
47
|
+
ErrorType.USER_ERROR,
|
48
|
+
ErrorLevel.ERROR,
|
49
|
+
status.HTTP_401_UNAUTHORIZED,
|
50
|
+
status.WS_1008_POLICY_VIOLATION,
|
51
|
+
)
|
52
|
+
INVALID_BEARER = (
|
53
|
+
AuthErrorCodes.INVALID_BEARER,
|
54
|
+
ErrorType.USER_ERROR,
|
55
|
+
ErrorLevel.ERROR,
|
56
|
+
status.HTTP_401_UNAUTHORIZED,
|
57
|
+
status.WS_1008_POLICY_VIOLATION,
|
58
|
+
)
|
59
|
+
EXPIRED_API_KEY = (
|
60
|
+
AuthErrorCodes.EXPIRED_API_KEY,
|
61
|
+
ErrorType.USER_ERROR,
|
62
|
+
ErrorLevel.ERROR,
|
63
|
+
status.HTTP_401_UNAUTHORIZED,
|
64
|
+
status.WS_1008_POLICY_VIOLATION,
|
65
|
+
)
|
66
|
+
EXPIRED_BEARER = (
|
67
|
+
AuthErrorCodes.EXPIRED_BEARER,
|
68
|
+
ErrorType.USER_ERROR,
|
69
|
+
ErrorLevel.ERROR,
|
70
|
+
status.HTTP_401_UNAUTHORIZED,
|
71
|
+
status.WS_1008_POLICY_VIOLATION,
|
72
|
+
)
|
73
|
+
NO_CREDENTIALS = (
|
74
|
+
AuthErrorCodes.NO_CREDENTIALS,
|
75
|
+
ErrorType.USER_ERROR,
|
76
|
+
ErrorLevel.ERROR,
|
77
|
+
status.HTTP_401_UNAUTHORIZED,
|
78
|
+
status.WS_1008_POLICY_VIOLATION,
|
79
|
+
)
|
80
|
+
INSUFFICIENT_SCOPES = (
|
81
|
+
AuthErrorCodes.INSUFFICIENT_SCOPES,
|
82
|
+
ErrorType.USER_ERROR,
|
83
|
+
ErrorLevel.ERROR,
|
84
|
+
status.HTTP_403_FORBIDDEN,
|
85
|
+
status.WS_1008_POLICY_VIOLATION,
|
86
|
+
)
|
87
|
+
UNKNOWN_ERROR = (
|
88
|
+
AuthErrorCodes.UNKNOWN_ERROR,
|
89
|
+
ErrorType.SERVER_ERROR,
|
90
|
+
ErrorLevel.ERROR,
|
91
|
+
status.HTTP_500_INTERNAL_SERVER_ERROR,
|
92
|
+
status.WS_1011_INTERNAL_ERROR,
|
93
|
+
)
|
94
|
+
|
95
|
+
|
96
|
+
handler = ExceptionHandler(callback=AuthError.from_identifier)
|
97
|
+
|
19
98
|
AUTHENTICATE_HEADER = "WWW-Authenticate"
|
20
99
|
BEARER_AUTH_SCHEME = "Bearer"
|
21
100
|
APIKEY_AUTH_SCHEME = "X-API-Key"
|
@@ -80,19 +159,17 @@ class AuthHandler:
|
|
80
159
|
return await self.client.login.verify_basic_auth(basic.username, basic.password)
|
81
160
|
|
82
161
|
async def _validate_scopes(
|
83
|
-
self, api_scopes: list[
|
84
|
-
) ->
|
162
|
+
self, api_scopes: list[str], user_scopes: list[str]
|
163
|
+
) -> None:
|
85
164
|
"""
|
86
165
|
Checks if the required scopes are a subset of the user scopes.
|
87
166
|
"""
|
88
167
|
if not set(api_scopes).issubset(user_scopes):
|
89
|
-
raise
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
+ ")",
|
95
|
-
),
|
168
|
+
raise handler.build_exception(
|
169
|
+
AuthErrorCodes.INSUFFICIENT_SCOPES,
|
170
|
+
"Insufficient scopes to access this resource (required: "
|
171
|
+
+ ", ".join(api_scopes)
|
172
|
+
+ ")",
|
96
173
|
)
|
97
174
|
|
98
175
|
async def _extract_message(self, e: ApiException) -> str:
|
@@ -119,33 +196,24 @@ class AuthHandler:
|
|
119
196
|
# Unfortunately, we cannot share the error messages defined in python/crypticorn/common/errors.py with the typescript client
|
120
197
|
message = await self._extract_message(e)
|
121
198
|
if message == "Invalid API key":
|
122
|
-
error =
|
199
|
+
error = AuthErrorCodes.INVALID_API_KEY
|
123
200
|
elif message == "API key expired":
|
124
|
-
error =
|
201
|
+
error = AuthErrorCodes.EXPIRED_API_KEY
|
125
202
|
elif message == "jwt expired":
|
126
|
-
error =
|
203
|
+
error = AuthErrorCodes.EXPIRED_BEARER
|
127
204
|
elif message == "Invalid basic authentication credentials":
|
128
|
-
error =
|
205
|
+
error = AuthErrorCodes.INVALID_BASIC_AUTH
|
129
206
|
else:
|
130
207
|
message = "Invalid bearer token"
|
131
208
|
error = (
|
132
|
-
|
209
|
+
AuthErrorCodes.INVALID_BEARER
|
133
210
|
) # jwt malformed, jwt not active (https://www.npmjs.com/package/jsonwebtoken#errors--codes)
|
134
|
-
return
|
135
|
-
|
136
|
-
error=error,
|
137
|
-
message=message,
|
138
|
-
),
|
139
|
-
)
|
211
|
+
return handler.build_exception(error, message)
|
212
|
+
|
140
213
|
elif isinstance(e, HTTPException):
|
141
214
|
return e
|
142
215
|
else:
|
143
|
-
return
|
144
|
-
content=ExceptionContent(
|
145
|
-
error=ApiError.UNKNOWN_ERROR,
|
146
|
-
message=str(e),
|
147
|
-
),
|
148
|
-
)
|
216
|
+
return handler.build_exception(AuthErrorCodes.UNKNOWN_ERROR, str(e))
|
149
217
|
|
150
218
|
async def api_key_auth(
|
151
219
|
self,
|
@@ -162,11 +230,9 @@ class AuthHandler:
|
|
162
230
|
bearer=None, api_key=api_key, basic=None, sec=sec
|
163
231
|
)
|
164
232
|
except HTTPException as e:
|
165
|
-
raise
|
166
|
-
|
167
|
-
|
168
|
-
message=e.detail.get("message"),
|
169
|
-
),
|
233
|
+
raise handler.build_exception(
|
234
|
+
e.detail.get("code"),
|
235
|
+
e.detail.get("message"),
|
170
236
|
headers={AUTHENTICATE_HEADER: APIKEY_AUTH_SCHEME},
|
171
237
|
)
|
172
238
|
|
@@ -188,11 +254,9 @@ class AuthHandler:
|
|
188
254
|
bearer=bearer, api_key=None, basic=None, sec=sec
|
189
255
|
)
|
190
256
|
except HTTPException as e:
|
191
|
-
raise
|
192
|
-
|
193
|
-
|
194
|
-
message=e.detail.get("message"),
|
195
|
-
),
|
257
|
+
raise handler.build_exception(
|
258
|
+
e.detail.get("code"),
|
259
|
+
e.detail.get("message"),
|
196
260
|
headers={AUTHENTICATE_HEADER: BEARER_AUTH_SCHEME},
|
197
261
|
)
|
198
262
|
|
@@ -208,11 +272,9 @@ class AuthHandler:
|
|
208
272
|
basic=credentials, bearer=None, api_key=None, sec=None
|
209
273
|
)
|
210
274
|
except HTTPException as e:
|
211
|
-
raise
|
212
|
-
|
213
|
-
|
214
|
-
message=e.detail.get("message"),
|
215
|
-
),
|
275
|
+
raise handler.build_exception(
|
276
|
+
e.detail.get("code"),
|
277
|
+
e.detail.get("message"),
|
216
278
|
headers={AUTHENTICATE_HEADER: BASIC_AUTH_SCHEME},
|
217
279
|
)
|
218
280
|
|
@@ -235,11 +297,9 @@ class AuthHandler:
|
|
235
297
|
basic=None, bearer=bearer, api_key=api_key, sec=sec
|
236
298
|
)
|
237
299
|
except HTTPException as e:
|
238
|
-
raise
|
239
|
-
|
240
|
-
|
241
|
-
message=e.detail.get("message"),
|
242
|
-
),
|
300
|
+
raise handler.build_exception(
|
301
|
+
e.detail.get("code"),
|
302
|
+
e.detail.get("message"),
|
243
303
|
headers={
|
244
304
|
AUTHENTICATE_HEADER: f"{BEARER_AUTH_SCHEME}, {APIKEY_AUTH_SCHEME}"
|
245
305
|
},
|
@@ -287,11 +347,9 @@ class AuthHandler:
|
|
287
347
|
if last_error:
|
288
348
|
raise last_error
|
289
349
|
else:
|
290
|
-
raise
|
291
|
-
|
292
|
-
|
293
|
-
message="No credentials provided. Check the WWW-Authenticate header for the available authentication methods.",
|
294
|
-
),
|
350
|
+
raise handler.build_exception(
|
351
|
+
AuthErrorCodes.NO_CREDENTIALS,
|
352
|
+
"No credentials provided. Check the WWW-Authenticate header for the available authentication methods.",
|
295
353
|
headers={
|
296
354
|
AUTHENTICATE_HEADER: f"{BEARER_AUTH_SCHEME}, {APIKEY_AUTH_SCHEME}, {BASIC_AUTH_SCHEME}"
|
297
355
|
},
|
@@ -0,0 +1,55 @@
|
|
1
|
+
"""Defines common enumerations used throughout the codebase for type safety and consistency."""
|
2
|
+
|
3
|
+
from enum import StrEnum
|
4
|
+
|
5
|
+
|
6
|
+
class Exchange(StrEnum):
|
7
|
+
"""All exchanges used in the crypticorn ecosystem. Refer to the APIs for support for a specific usecase (data, trading, etc.)."""
|
8
|
+
|
9
|
+
KUCOIN = "kucoin"
|
10
|
+
BINGX = "bingx"
|
11
|
+
BINANCE = "binance"
|
12
|
+
BYBIT = "bybit"
|
13
|
+
HYPERLIQUID = "hyperliquid"
|
14
|
+
BITGET = "bitget"
|
15
|
+
GATEIO = "gateio"
|
16
|
+
BITSTAMP = "bitstamp"
|
17
|
+
|
18
|
+
|
19
|
+
class MarketType(StrEnum):
|
20
|
+
"""
|
21
|
+
Market types
|
22
|
+
"""
|
23
|
+
|
24
|
+
SPOT = "spot"
|
25
|
+
FUTURES = "futures"
|
26
|
+
|
27
|
+
|
28
|
+
class ApiEnv(StrEnum):
|
29
|
+
"""The environment the API is being used with."""
|
30
|
+
|
31
|
+
PROD = "prod"
|
32
|
+
DEV = "dev"
|
33
|
+
LOCAL = "local"
|
34
|
+
DOCKER = "docker"
|
35
|
+
|
36
|
+
|
37
|
+
class BaseUrl(StrEnum):
|
38
|
+
"""The base URL to connect to the API."""
|
39
|
+
|
40
|
+
PROD = "https://api.crypticorn.com"
|
41
|
+
DEV = "https://api.crypticorn.dev"
|
42
|
+
LOCAL = "http://localhost"
|
43
|
+
DOCKER = "http://host.docker.internal"
|
44
|
+
|
45
|
+
@classmethod
|
46
|
+
def from_env(cls, env: ApiEnv) -> "BaseUrl":
|
47
|
+
"""Load the base URL from the API environment."""
|
48
|
+
if env == ApiEnv.PROD:
|
49
|
+
return cls.PROD
|
50
|
+
elif env == ApiEnv.DEV:
|
51
|
+
return cls.DEV
|
52
|
+
elif env == ApiEnv.LOCAL:
|
53
|
+
return cls.LOCAL
|
54
|
+
elif env == ApiEnv.DOCKER:
|
55
|
+
return cls.DOCKER
|
@@ -0,0 +1,25 @@
|
|
1
|
+
"""Comprehensive error handling system defining various API error types, HTTP exceptions, and error content structures."""
|
2
|
+
|
3
|
+
from enum import StrEnum
|
4
|
+
|
5
|
+
|
6
|
+
class ErrorType(StrEnum):
|
7
|
+
"""Type of the API error."""
|
8
|
+
|
9
|
+
USER_ERROR = "user error"
|
10
|
+
"""user error by people using our services"""
|
11
|
+
EXCHANGE_ERROR = "exchange error"
|
12
|
+
"""re-tryable error by the exchange or network conditions"""
|
13
|
+
SERVER_ERROR = "server error"
|
14
|
+
"""server error that needs a new version rollout for a fix"""
|
15
|
+
NO_ERROR = "no error"
|
16
|
+
"""error that does not need to be handled or does not affect the program or is a placeholder."""
|
17
|
+
|
18
|
+
|
19
|
+
class ErrorLevel(StrEnum):
|
20
|
+
"""Level of the API error."""
|
21
|
+
|
22
|
+
ERROR = "error"
|
23
|
+
INFO = "info"
|
24
|
+
SUCCESS = "success"
|
25
|
+
WARNING = "warning"
|