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.
Files changed (52) hide show
  1. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/LICENSE +1 -1
  2. crypticorn_utils-1.0.0rc1/MANIFEST.in +4 -0
  3. {crypticorn_utils-0.1.0rc1/crypticorn_utils.egg-info → crypticorn_utils-1.0.0rc1}/PKG-INFO +20 -5
  4. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/README.md +18 -0
  5. crypticorn_utils-1.0.0rc1/crypticorn_utils/__init__.py +50 -0
  6. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/_migration.py +2 -1
  7. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/ansi_colors.py +1 -4
  8. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/auth.py +112 -54
  9. crypticorn_utils-1.0.0rc1/crypticorn_utils/enums.py +55 -0
  10. crypticorn_utils-1.0.0rc1/crypticorn_utils/errors.py +25 -0
  11. crypticorn_utils-1.0.0rc1/crypticorn_utils/exceptions.py +288 -0
  12. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/logging.py +5 -19
  13. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/metrics.py +1 -2
  14. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/middleware.py +7 -40
  15. crypticorn_utils-1.0.0rc1/crypticorn_utils/utils.py +42 -0
  16. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/warnings.py +0 -28
  17. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1/crypticorn_utils.egg-info}/PKG-INFO +20 -5
  18. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/SOURCES.txt +2 -14
  19. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/requires.txt +0 -1
  20. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/pyproject.toml +15 -4
  21. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/requirements/dev.txt +0 -1
  22. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/requirements/main.txt +0 -2
  23. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/tests/test_auth_client.py +27 -31
  24. crypticorn_utils-1.0.0rc1/tests/test_exceptions.py +456 -0
  25. crypticorn_utils-0.1.0rc1/MANIFEST.in +0 -3
  26. crypticorn_utils-0.1.0rc1/crypticorn_utils/__init__.py +0 -16
  27. crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/__init__.py +0 -4
  28. crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/__main__.py +0 -17
  29. crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/init.py +0 -127
  30. crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/templates/auth.py +0 -33
  31. crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/version.py +0 -8
  32. crypticorn_utils-0.1.0rc1/crypticorn_utils/enums.py +0 -175
  33. crypticorn_utils-0.1.0rc1/crypticorn_utils/errors.py +0 -915
  34. crypticorn_utils-0.1.0rc1/crypticorn_utils/exceptions.py +0 -183
  35. crypticorn_utils-0.1.0rc1/crypticorn_utils/mixins.py +0 -68
  36. crypticorn_utils-0.1.0rc1/crypticorn_utils/openapi.py +0 -10
  37. crypticorn_utils-0.1.0rc1/crypticorn_utils/router/admin_router.py +0 -117
  38. crypticorn_utils-0.1.0rc1/crypticorn_utils/router/status_router.py +0 -36
  39. crypticorn_utils-0.1.0rc1/crypticorn_utils/utils.py +0 -93
  40. crypticorn_utils-0.1.0rc1/tests/test_common_routers.py +0 -111
  41. crypticorn_utils-0.1.0rc1/tests/test_config.py +0 -22
  42. crypticorn_utils-0.1.0rc1/tests/test_enums.py +0 -44
  43. crypticorn_utils-0.1.0rc1/tests/test_errors.py +0 -63
  44. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/decorators.py +0 -0
  45. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils/pagination.py +0 -0
  46. crypticorn_utils-0.1.0rc1/crypticorn_utils/cli/templates/__init__.py → crypticorn_utils-1.0.0rc1/crypticorn_utils/py.typed +0 -0
  47. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/dependency_links.txt +0 -0
  48. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/entry_points.txt +0 -0
  49. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/crypticorn_utils.egg-info/top_level.txt +0 -0
  50. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/requirements/test.txt +0 -0
  51. {crypticorn_utils-0.1.0rc1 → crypticorn_utils-1.0.0rc1}/setup.cfg +0 -0
  52. {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.
@@ -0,0 +1,4 @@
1
+ include crypticorn_utils/py.typed
2
+ include README.md
3
+ include LICENSE
4
+ include
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn_utils
3
- Version: 0.1.0rc1
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.9
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 = False
13
+ has_migrated = True
@@ -1,7 +1,4 @@
1
- try:
2
- from enum import StrEnum
3
- except ImportError:
4
- from strenum import StrEnum
1
+ from enum import StrEnum
5
2
 
6
3
 
7
4
  class AnsiColors(StrEnum):
@@ -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 Scope, BaseUrl
7
- from crypticorn_utils.exceptions import ApiError, ExceptionContent, HTTPException
8
- from fastapi import Depends, Query
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[Scope], user_scopes: list[Scope]
84
- ) -> bool:
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 HTTPException(
90
- content=ExceptionContent(
91
- error=ApiError.INSUFFICIENT_SCOPES,
92
- message="Insufficient scopes to access this resource (required: "
93
- + ", ".join(api_scopes)
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 = ApiError.INVALID_API_KEY
199
+ error = AuthErrorCodes.INVALID_API_KEY
123
200
  elif message == "API key expired":
124
- error = ApiError.EXPIRED_API_KEY
201
+ error = AuthErrorCodes.EXPIRED_API_KEY
125
202
  elif message == "jwt expired":
126
- error = ApiError.EXPIRED_BEARER
203
+ error = AuthErrorCodes.EXPIRED_BEARER
127
204
  elif message == "Invalid basic authentication credentials":
128
- error = ApiError.INVALID_BASIC_AUTH
205
+ error = AuthErrorCodes.INVALID_BASIC_AUTH
129
206
  else:
130
207
  message = "Invalid bearer token"
131
208
  error = (
132
- ApiError.INVALID_BEARER
209
+ AuthErrorCodes.INVALID_BEARER
133
210
  ) # jwt malformed, jwt not active (https://www.npmjs.com/package/jsonwebtoken#errors--codes)
134
- return HTTPException(
135
- content=ExceptionContent(
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 HTTPException(
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 HTTPException(
166
- content=ExceptionContent(
167
- error=ApiError.from_json(e.detail),
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 HTTPException(
192
- content=ExceptionContent(
193
- error=ApiError.from_json(e.detail),
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 HTTPException(
212
- content=ExceptionContent(
213
- error=ApiError.from_json(e.detail),
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 HTTPException(
239
- content=ExceptionContent(
240
- error=ApiError.from_json(e.detail),
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 HTTPException(
291
- content=ExceptionContent(
292
- error=ApiError.NO_CREDENTIALS,
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"