crypticorn 2.8.0rc9__py3-none-any.whl → 2.8.2__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.
- crypticorn/__init__.py +0 -4
- crypticorn/cli/init.py +2 -2
- crypticorn/common/__init__.py +0 -2
- crypticorn/common/ansi_colors.py +1 -2
- crypticorn/common/auth.py +2 -2
- crypticorn/common/enums.py +0 -2
- crypticorn/common/errors.py +5 -8
- crypticorn/common/exceptions.py +20 -23
- crypticorn/common/logging.py +8 -6
- crypticorn/common/middleware.py +1 -2
- crypticorn/common/mixins.py +3 -10
- crypticorn/common/pagination.py +0 -2
- crypticorn/common/router/admin_router.py +7 -9
- crypticorn/common/router/status_router.py +1 -8
- crypticorn/common/scopes.py +3 -3
- crypticorn/common/urls.py +0 -9
- crypticorn/common/utils.py +8 -16
- crypticorn/klines/client/__init__.py +9 -1
- crypticorn/klines/client/api/__init__.py +1 -0
- crypticorn/klines/client/api/admin_api.py +1455 -0
- crypticorn/klines/client/api/change_in_timeframe_api.py +24 -20
- crypticorn/klines/client/api/funding_rates_api.py +12 -10
- crypticorn/klines/client/api/ohlcv_data_api.py +37 -24
- crypticorn/klines/client/api/status_api.py +8 -235
- crypticorn/klines/client/api/symbols_api.py +12 -9
- crypticorn/klines/client/api/udf_api.py +6 -6
- crypticorn/klines/client/models/__init__.py +8 -1
- crypticorn/klines/client/models/api_error_identifier.py +115 -0
- crypticorn/klines/client/models/api_error_level.py +37 -0
- crypticorn/klines/client/models/api_error_type.py +37 -0
- crypticorn/klines/client/models/exception_detail.py +6 -3
- crypticorn/klines/client/models/funding_rate.py +6 -12
- crypticorn/klines/client/models/funding_rate_response.py +103 -0
- crypticorn/klines/client/models/internal_exchange.py +39 -0
- crypticorn/klines/client/models/log_level.py +38 -0
- crypticorn/klines/client/models/market_type.py +35 -0
- crypticorn/klines/client/models/{ohlcv_history.py → ohlcv.py} +12 -13
- crypticorn/klines/client/models/search_symbol.py +3 -4
- crypticorn/klines/client/models/udf_config.py +2 -1
- crypticorn/klines/main.py +1 -13
- crypticorn/metrics/client/api/admin_api.py +22 -19
- crypticorn/metrics/client/api/status_api.py +6 -6
- crypticorn/metrics/client/configuration.py +4 -2
- {crypticorn-2.8.0rc9.dist-info → crypticorn-2.8.2.dist-info}/METADATA +1 -1
- {crypticorn-2.8.0rc9.dist-info → crypticorn-2.8.2.dist-info}/RECORD +48 -42
- crypticorn/common/openapi.py +0 -11
- crypticorn/common/warnings.py +0 -63
- {crypticorn-2.8.0rc9.dist-info → crypticorn-2.8.2.dist-info}/WHEEL +0 -0
- {crypticorn-2.8.0rc9.dist-info → crypticorn-2.8.2.dist-info}/entry_points.txt +0 -0
- {crypticorn-2.8.0rc9.dist-info → crypticorn-2.8.2.dist-info}/top_level.txt +0 -0
crypticorn/__init__.py
CHANGED
@@ -6,13 +6,9 @@ We adhere to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
You can find the full Changelog [below](#changelog).
|
7
7
|
"""
|
8
8
|
|
9
|
-
import warnings
|
10
|
-
import logging
|
11
9
|
from crypticorn.common.logging import configure_logging
|
12
10
|
|
13
|
-
warnings.filterwarnings("default", "", DeprecationWarning)
|
14
11
|
configure_logging()
|
15
|
-
logging.captureWarnings(True)
|
16
12
|
|
17
13
|
from crypticorn.client import ApiClient
|
18
14
|
|
crypticorn/cli/init.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import click
|
2
2
|
from pathlib import Path
|
3
3
|
import subprocess
|
4
|
-
import importlib.resources
|
4
|
+
import importlib.resources
|
5
5
|
import crypticorn.cli.templates as templates
|
6
6
|
|
7
7
|
|
@@ -19,7 +19,7 @@ def get_git_root() -> Path:
|
|
19
19
|
|
20
20
|
def copy_template(template_name: str, target_path: Path):
|
21
21
|
"""Copy a template file to the target path."""
|
22
|
-
with
|
22
|
+
with importlib.resources.files(templates).joinpath(template_name).open(
|
23
23
|
"r"
|
24
24
|
) as template_file:
|
25
25
|
content = template_file.read()
|
crypticorn/common/__init__.py
CHANGED
@@ -11,7 +11,5 @@ from crypticorn.common.pagination import *
|
|
11
11
|
from crypticorn.common.logging import *
|
12
12
|
from crypticorn.common.ansi_colors import *
|
13
13
|
from crypticorn.common.middleware import *
|
14
|
-
from crypticorn.common.warnings import *
|
15
|
-
from crypticorn.common.openapi import *
|
16
14
|
from crypticorn.common.router.status_router import router as status_router
|
17
15
|
from crypticorn.common.router.admin_router import router as admin_router
|
crypticorn/common/ansi_colors.py
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
from enum import StrEnum
|
2
|
+
from typing import TYPE_CHECKING
|
2
3
|
|
3
4
|
|
4
5
|
class AnsiColors(StrEnum):
|
5
|
-
"""Provides a collection of ANSI color codes for terminal text formatting, including regular, bright, and bold text colors. Useful for creating colorful and readable console output."""
|
6
|
-
|
7
6
|
# Regular Text Colors
|
8
7
|
BLACK = "\033[30m" # black
|
9
8
|
RED = "\033[31m" # red
|
crypticorn/common/auth.py
CHANGED
@@ -38,8 +38,8 @@ class AuthHandler:
|
|
38
38
|
"""
|
39
39
|
Middleware for verifying API requests. Verifies the validity of the authentication token, scopes, etc.
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
@param base_url: The base URL of the API.
|
42
|
+
@param api_version: The version of the API.
|
43
43
|
"""
|
44
44
|
|
45
45
|
def __init__(
|
crypticorn/common/enums.py
CHANGED
crypticorn/common/errors.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
-
"""Comprehensive error handling system defining various API error types, HTTP exceptions, and error content structures."""
|
2
|
-
|
3
1
|
from enum import Enum, StrEnum
|
4
2
|
from fastapi import status
|
5
3
|
from crypticorn.common.mixins import ExcludeEnumMixin, ApiErrorFallback
|
6
4
|
|
7
5
|
|
8
6
|
class ApiErrorType(ExcludeEnumMixin, StrEnum):
|
9
|
-
"""Type of
|
7
|
+
"""Type of API error"""
|
10
8
|
|
11
9
|
USER_ERROR = "user error"
|
12
10
|
"""user error by people using our services"""
|
@@ -19,7 +17,7 @@ class ApiErrorType(ExcludeEnumMixin, StrEnum):
|
|
19
17
|
|
20
18
|
|
21
19
|
class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
|
22
|
-
"""
|
20
|
+
"""API error identifiers"""
|
23
21
|
|
24
22
|
ALLOCATION_BELOW_EXPOSURE = "allocation_below_current_exposure"
|
25
23
|
ALLOCATION_BELOW_MINIMUM = "allocation_below_min_amount"
|
@@ -105,7 +103,7 @@ class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
|
|
105
103
|
|
106
104
|
|
107
105
|
class ApiErrorLevel(ExcludeEnumMixin, StrEnum):
|
108
|
-
"""
|
106
|
+
"""API error levels"""
|
109
107
|
|
110
108
|
ERROR = "error"
|
111
109
|
INFO = "info"
|
@@ -114,8 +112,7 @@ class ApiErrorLevel(ExcludeEnumMixin, StrEnum):
|
|
114
112
|
|
115
113
|
|
116
114
|
class ApiError(ExcludeEnumMixin, Enum, metaclass=ApiErrorFallback):
|
117
|
-
|
118
|
-
"""Crypticorn API error enumeration."""
|
115
|
+
"""API error codes. Fallback to UNKNOWN_ERROR for error codes not yet published to PyPI."""
|
119
116
|
|
120
117
|
ALLOCATION_BELOW_EXPOSURE = (
|
121
118
|
ApiErrorIdentifier.ALLOCATION_BELOW_EXPOSURE,
|
@@ -521,7 +518,7 @@ class ApiError(ExcludeEnumMixin, Enum, metaclass=ApiErrorFallback):
|
|
521
518
|
|
522
519
|
|
523
520
|
class StatusCodeMapper:
|
524
|
-
"""
|
521
|
+
"""Map API errors to HTTP status codes."""
|
525
522
|
|
526
523
|
_mapping = {
|
527
524
|
# Authentication/Authorization
|
crypticorn/common/exceptions.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional, Dict, Any
|
1
|
+
from typing import Optional, Dict, Any, Literal
|
2
2
|
from enum import StrEnum
|
3
3
|
from pydantic import BaseModel, Field
|
4
4
|
from fastapi import HTTPException as FastAPIHTTPException, Request, FastAPI
|
@@ -8,18 +8,16 @@ from crypticorn.common import ApiError, ApiErrorIdentifier, ApiErrorType, ApiErr
|
|
8
8
|
import logging
|
9
9
|
import json
|
10
10
|
|
11
|
-
|
11
|
+
logger = logging.getLogger("crypticorn")
|
12
12
|
|
13
13
|
|
14
|
-
class
|
15
|
-
"""The protocol the exception is called from"""
|
16
|
-
|
14
|
+
class ExceptionType(StrEnum):
|
17
15
|
HTTP = "http"
|
18
16
|
WEBSOCKET = "websocket"
|
19
17
|
|
20
18
|
|
21
19
|
class ExceptionDetail(BaseModel):
|
22
|
-
"""
|
20
|
+
"""This is the detail of the exception. It is used to enrich the exception with additional information by unwrapping the ApiError into its components."""
|
23
21
|
|
24
22
|
message: Optional[str] = Field(None, description="An additional error message")
|
25
23
|
code: ApiErrorIdentifier = Field(..., description="The unique error code")
|
@@ -30,14 +28,14 @@ class ExceptionDetail(BaseModel):
|
|
30
28
|
|
31
29
|
|
32
30
|
class ExceptionContent(BaseModel):
|
33
|
-
"""
|
31
|
+
"""This is the detail of the exception. Pass an ApiError to the constructor and an optional human readable message."""
|
34
32
|
|
35
33
|
error: ApiError = Field(..., description="The unique error code")
|
36
34
|
message: Optional[str] = Field(None, description="An additional error message")
|
37
35
|
details: Any = Field(None, description="Additional details about the error")
|
38
36
|
|
39
37
|
def enrich(
|
40
|
-
self, _type: Optional[
|
38
|
+
self, _type: Optional[ExceptionType] = ExceptionType.HTTP
|
41
39
|
) -> ExceptionDetail:
|
42
40
|
return ExceptionDetail(
|
43
41
|
message=self.message,
|
@@ -46,7 +44,7 @@ class ExceptionContent(BaseModel):
|
|
46
44
|
level=self.error.level,
|
47
45
|
status_code=(
|
48
46
|
self.error.http_code
|
49
|
-
if _type ==
|
47
|
+
if _type == ExceptionType.HTTP
|
50
48
|
else self.error.websocket_code
|
51
49
|
),
|
52
50
|
details=self.details,
|
@@ -56,14 +54,14 @@ class ExceptionContent(BaseModel):
|
|
56
54
|
class HTTPException(FastAPIHTTPException):
|
57
55
|
"""A custom HTTP exception wrapper around FastAPI's HTTPException.
|
58
56
|
It allows for a more structured way to handle errors, with a message and an error code. The status code is being derived from the detail's error.
|
59
|
-
The ApiError class is the source of truth. If the error is not yet implemented, there are fallbacks
|
57
|
+
The ApiError class is the source of truth for everything. If the error is not yet implemented, there are fallbacks to avoid errors while testing.
|
60
58
|
"""
|
61
59
|
|
62
60
|
def __init__(
|
63
61
|
self,
|
64
62
|
content: ExceptionContent,
|
65
63
|
headers: Optional[Dict[str, str]] = None,
|
66
|
-
_type: Optional[
|
64
|
+
_type: Optional[ExceptionType] = ExceptionType.HTTP,
|
67
65
|
):
|
68
66
|
self.content = content
|
69
67
|
self.headers = headers
|
@@ -84,11 +82,11 @@ class WebSocketException(HTTPException):
|
|
84
82
|
def __init__(
|
85
83
|
self, content: ExceptionContent, headers: Optional[Dict[str, str]] = None
|
86
84
|
):
|
87
|
-
super().__init__(content, headers, _type=
|
85
|
+
super().__init__(content, headers, _type=ExceptionType.WEBSOCKET)
|
88
86
|
|
89
87
|
@classmethod
|
90
88
|
def from_http_exception(cls, http_exception: HTTPException):
|
91
|
-
"""
|
89
|
+
"""This is a helper method to convert an HTTPException to a WebSocketException."""
|
92
90
|
return WebSocketException(
|
93
91
|
content=http_exception.content,
|
94
92
|
headers=http_exception.headers,
|
@@ -96,47 +94,46 @@ class WebSocketException(HTTPException):
|
|
96
94
|
|
97
95
|
|
98
96
|
async def general_handler(request: Request, exc: Exception) -> JSONResponse:
|
99
|
-
"""
|
97
|
+
"""This is the default exception handler for all exceptions."""
|
100
98
|
body = ExceptionContent(message=str(exc), error=ApiError.UNKNOWN_ERROR)
|
101
99
|
res = JSONResponse(
|
102
100
|
status_code=body.enrich().status_code,
|
103
101
|
content=HTTPException(content=body).detail,
|
104
102
|
)
|
105
|
-
|
103
|
+
logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
106
104
|
return res
|
107
105
|
|
108
106
|
|
109
107
|
async def request_validation_handler(
|
110
108
|
request: Request, exc: RequestValidationError
|
111
109
|
) -> JSONResponse:
|
112
|
-
"""
|
110
|
+
"""This is the exception handler for all request validation errors."""
|
113
111
|
body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_REQUEST)
|
114
112
|
res = JSONResponse(
|
115
113
|
status_code=body.enrich().status_code,
|
116
114
|
content=HTTPException(content=body).detail,
|
117
115
|
)
|
118
|
-
|
116
|
+
logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
119
117
|
return res
|
120
118
|
|
121
119
|
|
122
120
|
async def response_validation_handler(
|
123
121
|
request: Request, exc: ResponseValidationError
|
124
122
|
) -> JSONResponse:
|
125
|
-
"""
|
123
|
+
"""This is the exception handler for all response validation errors."""
|
126
124
|
body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_RESPONSE)
|
127
125
|
res = JSONResponse(
|
128
126
|
status_code=body.enrich().status_code,
|
129
127
|
content=HTTPException(content=body).detail,
|
130
128
|
)
|
131
|
-
|
129
|
+
logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
132
130
|
return res
|
133
131
|
|
134
132
|
|
135
133
|
async def http_handler(request: Request, exc: HTTPException) -> JSONResponse:
|
136
|
-
"""
|
137
|
-
|
138
|
-
|
139
|
-
return res
|
134
|
+
"""This is the exception handler for HTTPExceptions. It unwraps the HTTPException and returns the detail in a flat JSON response."""
|
135
|
+
logger.error(f"HTTP error: {exc.detail}")
|
136
|
+
return JSONResponse(status_code=exc.status_code, content=exc.detail)
|
140
137
|
|
141
138
|
|
142
139
|
def register_exception_handlers(app: FastAPI):
|
crypticorn/common/logging.py
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
# shared_logger.py
|
3
4
|
import logging
|
4
5
|
import sys
|
6
|
+
from contextvars import ContextVar
|
7
|
+
from contextlib import asynccontextmanager
|
8
|
+
import json
|
9
|
+
from pydantic import BaseModel
|
5
10
|
from enum import StrEnum
|
6
11
|
from crypticorn.common.mixins import ValidateEnumMixin
|
7
12
|
from crypticorn.common.ansi_colors import AnsiColors as C
|
@@ -18,7 +23,6 @@ class LogLevel(ValidateEnumMixin, StrEnum):
|
|
18
23
|
|
19
24
|
@classmethod
|
20
25
|
def get_color(cls, level: str) -> str:
|
21
|
-
"""Get the ansi color based on the log level."""
|
22
26
|
if level == cls.DEBUG:
|
23
27
|
return C.GREEN_BRIGHT
|
24
28
|
elif level == cls.INFO:
|
@@ -34,12 +38,10 @@ class LogLevel(ValidateEnumMixin, StrEnum):
|
|
34
38
|
|
35
39
|
@staticmethod
|
36
40
|
def get_level(level: "LogLevel") -> int:
|
37
|
-
"""Get the integer value from a log level name."""
|
38
41
|
return logging._nameToLevel.get(level, logging.INFO)
|
39
42
|
|
40
43
|
@staticmethod
|
41
44
|
def get_name(level: int) -> "LogLevel":
|
42
|
-
"""Get the level name from the integer value of a log level."""
|
43
45
|
return LogLevel(logging._levelToName.get(level, "INFO"))
|
44
46
|
|
45
47
|
|
@@ -52,7 +54,7 @@ _LOGFORMAT = (
|
|
52
54
|
_DATEFMT = "%Y-%m-%d %H:%M:%S.%f:"
|
53
55
|
|
54
56
|
|
55
|
-
class
|
57
|
+
class CustomFormatter(logging.Formatter):
|
56
58
|
def __init__(self, *args, **kwargs):
|
57
59
|
super().__init__(*args, **kwargs)
|
58
60
|
|
@@ -97,7 +99,7 @@ def configure_logging(
|
|
97
99
|
# Configure stdout handler
|
98
100
|
stdout_handler = logging.StreamHandler(sys.stdout)
|
99
101
|
stdout_handler.setLevel(stdout_level)
|
100
|
-
stdout_handler.setFormatter(
|
102
|
+
stdout_handler.setFormatter(CustomFormatter(fmt=fmt, datefmt=datefmt))
|
101
103
|
for filter in filters:
|
102
104
|
stdout_handler.addFilter(filter)
|
103
105
|
logger.addHandler(stdout_handler)
|
@@ -109,7 +111,7 @@ def configure_logging(
|
|
109
111
|
log_file, maxBytes=10 * 1024 * 1024, backupCount=5
|
110
112
|
)
|
111
113
|
file_handler.setLevel(file_level)
|
112
|
-
file_handler.setFormatter(
|
114
|
+
file_handler.setFormatter(CustomFormatter(fmt=fmt, datefmt=datefmt))
|
113
115
|
for filter in filters:
|
114
116
|
file_handler.addFilter(filter)
|
115
117
|
logger.addHandler(file_handler)
|
crypticorn/common/middleware.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from fastapi import FastAPI
|
2
2
|
from fastapi.middleware.cors import CORSMiddleware
|
3
3
|
from crypticorn.common.logging import configure_logging
|
4
|
-
|
4
|
+
import logging
|
5
5
|
|
6
6
|
|
7
7
|
def add_cors_middleware(app: "FastAPI"):
|
@@ -18,7 +18,6 @@ def add_cors_middleware(app: "FastAPI"):
|
|
18
18
|
)
|
19
19
|
|
20
20
|
|
21
|
-
@asynccontextmanager
|
22
21
|
async def default_lifespan(app: FastAPI):
|
23
22
|
"""Default lifespan for the applications.
|
24
23
|
This is used to configure the logging for the application.
|
crypticorn/common/mixins.py
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
from enum import EnumMeta
|
2
2
|
import logging
|
3
|
-
import warnings
|
4
|
-
from crypticorn.common.warnings import CrypticornDeprecatedSince28
|
5
3
|
|
6
|
-
|
4
|
+
logger = logging.getLogger("uvicorn")
|
7
5
|
|
8
6
|
|
9
7
|
class ValidateEnumMixin:
|
@@ -37,12 +35,7 @@ class ValidateEnumMixin:
|
|
37
35
|
|
38
36
|
# This Mixin will be removed in a future version. And has no effect from now on
|
39
37
|
class ExcludeEnumMixin:
|
40
|
-
"""
|
41
|
-
|
42
|
-
warnings.warn(
|
43
|
-
"The `ExcludeEnumMixin` class is deprecated. Should be removed from enums inheriting this class.",
|
44
|
-
category=CrypticornDeprecatedSince28,
|
45
|
-
)
|
38
|
+
"""Mixin to exclude enum from OpenAPI schema. We use this to avoid duplicating enums when generating client code from the openapi spec."""
|
46
39
|
|
47
40
|
@classmethod
|
48
41
|
def __get_pydantic_json_schema__(cls, core_schema, handler):
|
@@ -58,7 +51,7 @@ class ApiErrorFallback(EnumMeta):
|
|
58
51
|
# Let Pydantic/internal stuff pass silently ! fragile
|
59
52
|
if name.startswith("__"):
|
60
53
|
raise AttributeError(name)
|
61
|
-
|
54
|
+
logger.warning(
|
62
55
|
f"Unknown enum member '{name}' - update crypticorn package or check for typos"
|
63
56
|
)
|
64
57
|
return cls.UNKNOWN_ERROR
|
crypticorn/common/pagination.py
CHANGED
@@ -6,7 +6,7 @@ ONLY ALLOW ACCESS TO THIS ROUTER WITH ADMIN SCOPES.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
import os
|
9
|
-
import
|
9
|
+
import importlib.metadata
|
10
10
|
import threading
|
11
11
|
import time
|
12
12
|
import psutil
|
@@ -90,11 +90,9 @@ def list_installed_packages(
|
|
90
90
|
)
|
91
91
|
) -> list:
|
92
92
|
"""Return a list of installed packages and versions."""
|
93
|
-
|
94
|
-
[
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
key=lambda x: next(iter(x)),
|
100
|
-
)
|
93
|
+
packages = {
|
94
|
+
dist.metadata["Name"]: dist.version
|
95
|
+
for dist in importlib.metadata.distributions()
|
96
|
+
if include is None or dist.metadata["Name"] in include
|
97
|
+
}
|
98
|
+
return dict(sorted(packages.items()))
|
@@ -1,10 +1,3 @@
|
|
1
|
-
"""
|
2
|
-
This module contains the status router for the API.
|
3
|
-
It provides endpoints for checking the status of the API and get the server's time.
|
4
|
-
SHOULD ALLOW ACCESS TO THIS ROUTER WITHOUT.
|
5
|
-
>>> app.include_router(status_router)
|
6
|
-
"""
|
7
|
-
|
8
1
|
from datetime import datetime
|
9
2
|
from typing import Literal
|
10
3
|
from fastapi import APIRouter, Request
|
@@ -13,7 +6,7 @@ router = APIRouter(tags=["Status"], prefix="")
|
|
13
6
|
|
14
7
|
|
15
8
|
@router.get("/", operation_id="ping")
|
16
|
-
async def ping(request: Request) ->
|
9
|
+
async def ping(request: Request) -> str:
|
17
10
|
"""
|
18
11
|
Returns 'OK' if the API is running.
|
19
12
|
"""
|
crypticorn/common/scopes.py
CHANGED
@@ -54,7 +54,7 @@ class Scope(StrEnum):
|
|
54
54
|
|
55
55
|
@classmethod
|
56
56
|
def admin_scopes(cls) -> list["Scope"]:
|
57
|
-
"""Scopes that are only available to admins
|
57
|
+
"""Scopes that are only available to admins"""
|
58
58
|
return [
|
59
59
|
cls.WRITE_TRADE_STRATEGIES,
|
60
60
|
cls.WRITE_PAY_PRODUCTS,
|
@@ -64,14 +64,14 @@ class Scope(StrEnum):
|
|
64
64
|
|
65
65
|
@classmethod
|
66
66
|
def internal_scopes(cls) -> list["Scope"]:
|
67
|
-
"""Scopes that are only available to internal services
|
67
|
+
"""Scopes that are only available to internal services"""
|
68
68
|
return [
|
69
69
|
cls.WRITE_TRADE_ACTIONS,
|
70
70
|
]
|
71
71
|
|
72
72
|
@classmethod
|
73
73
|
def purchaseable_scopes(cls) -> list["Scope"]:
|
74
|
-
"""Scopes that can be purchased
|
74
|
+
"""Scopes that can be purchased"""
|
75
75
|
return [
|
76
76
|
cls.READ_PREDICTIONS,
|
77
77
|
]
|
crypticorn/common/urls.py
CHANGED
@@ -3,8 +3,6 @@ from crypticorn.common.enums import ValidateEnumMixin
|
|
3
3
|
|
4
4
|
|
5
5
|
class ApiEnv(StrEnum):
|
6
|
-
"""The environment the API is being used with."""
|
7
|
-
|
8
6
|
PROD = "prod"
|
9
7
|
DEV = "dev"
|
10
8
|
LOCAL = "local"
|
@@ -12,8 +10,6 @@ class ApiEnv(StrEnum):
|
|
12
10
|
|
13
11
|
|
14
12
|
class BaseUrl(StrEnum):
|
15
|
-
"""The base URL to connect to the API."""
|
16
|
-
|
17
13
|
PROD = "https://api.crypticorn.com"
|
18
14
|
DEV = "https://api.crypticorn.dev"
|
19
15
|
LOCAL = "http://localhost"
|
@@ -21,7 +17,6 @@ class BaseUrl(StrEnum):
|
|
21
17
|
|
22
18
|
@classmethod
|
23
19
|
def from_env(cls, env: ApiEnv) -> "BaseUrl":
|
24
|
-
"""Load the base URL from the API environment."""
|
25
20
|
if env == ApiEnv.PROD:
|
26
21
|
return cls.PROD
|
27
22
|
elif env == ApiEnv.DEV:
|
@@ -33,14 +28,10 @@ class BaseUrl(StrEnum):
|
|
33
28
|
|
34
29
|
|
35
30
|
class ApiVersion(StrEnum):
|
36
|
-
"""Versions to use for the microservice APIs."""
|
37
|
-
|
38
31
|
V1 = "v1"
|
39
32
|
|
40
33
|
|
41
34
|
class Service(ValidateEnumMixin, StrEnum):
|
42
|
-
"""The microservices available to connect to through the API"""
|
43
|
-
|
44
35
|
HIVE = "hive"
|
45
36
|
KLINES = "klines"
|
46
37
|
PAY = "pay"
|
crypticorn/common/utils.py
CHANGED
@@ -1,14 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
from typing import Any
|
1
|
+
from typing import Any, Union
|
4
2
|
from decimal import Decimal
|
5
3
|
import string
|
6
4
|
import random
|
7
|
-
import
|
8
|
-
import
|
5
|
+
from fastapi import status
|
6
|
+
from typing_extensions import deprecated
|
9
7
|
|
10
|
-
from crypticorn.common
|
11
|
-
from crypticorn.common.warnings import CrypticornDeprecatedSince25
|
8
|
+
from crypticorn.common import ApiError, HTTPException, ExceptionContent
|
12
9
|
|
13
10
|
|
14
11
|
def throw_if_none(
|
@@ -36,9 +33,7 @@ def gen_random_id(length: int = 20) -> str:
|
|
36
33
|
return "".join(random.choice(charset) for _ in range(length))
|
37
34
|
|
38
35
|
|
39
|
-
@
|
40
|
-
"The `is_equal` method is deprecated; use `math.is_close` instead.", category=None
|
41
|
-
)
|
36
|
+
@deprecated("Use math.isclose instead. Will be removed in a future version.")
|
42
37
|
def is_equal(
|
43
38
|
a: float | Decimal,
|
44
39
|
b: float | Decimal,
|
@@ -48,10 +43,6 @@ def is_equal(
|
|
48
43
|
"""
|
49
44
|
Compare two Decimal numbers for approximate equality.
|
50
45
|
"""
|
51
|
-
warnings.warn(
|
52
|
-
"The `is_equal` method is deprecated; use `math.is_close` instead.",
|
53
|
-
category=CrypticornDeprecatedSince25,
|
54
|
-
)
|
55
46
|
if not isinstance(a, Decimal):
|
56
47
|
a = Decimal(str(a))
|
57
48
|
if not isinstance(b, Decimal):
|
@@ -65,12 +56,13 @@ def is_equal(
|
|
65
56
|
|
66
57
|
def optional_import(module_name: str, extra_name: str) -> Any:
|
67
58
|
"""
|
68
|
-
|
59
|
+
Import a module optionally.
|
69
60
|
"""
|
70
61
|
try:
|
71
62
|
return __import__(module_name)
|
72
63
|
except ImportError as e:
|
64
|
+
extra = f"[{extra_name}]"
|
73
65
|
raise ImportError(
|
74
66
|
f"Optional dependency '{module_name}' is required for this feature. "
|
75
|
-
f"Install it with: pip install crypticorn
|
67
|
+
f"Install it with: pip install crypticorn{extra}"
|
76
68
|
) from e
|
@@ -17,6 +17,7 @@ Do not edit the class manually.
|
|
17
17
|
__version__ = "1.0.0"
|
18
18
|
|
19
19
|
# import apis into sdk package
|
20
|
+
from crypticorn.klines.client.api.admin_api import AdminApi
|
20
21
|
from crypticorn.klines.client.api.change_in_timeframe_api import ChangeInTimeframeApi
|
21
22
|
from crypticorn.klines.client.api.funding_rates_api import FundingRatesApi
|
22
23
|
from crypticorn.klines.client.api.ohlcv_data_api import OHLCVDataApi
|
@@ -36,10 +37,17 @@ from crypticorn.klines.client.exceptions import ApiAttributeError
|
|
36
37
|
from crypticorn.klines.client.exceptions import ApiException
|
37
38
|
|
38
39
|
# import models into sdk package
|
40
|
+
from crypticorn.klines.client.models.api_error_identifier import ApiErrorIdentifier
|
41
|
+
from crypticorn.klines.client.models.api_error_level import ApiErrorLevel
|
42
|
+
from crypticorn.klines.client.models.api_error_type import ApiErrorType
|
39
43
|
from crypticorn.klines.client.models.change_in_timeframe import ChangeInTimeframe
|
40
44
|
from crypticorn.klines.client.models.exception_detail import ExceptionDetail
|
41
45
|
from crypticorn.klines.client.models.funding_rate import FundingRate
|
42
|
-
from crypticorn.klines.client.models.
|
46
|
+
from crypticorn.klines.client.models.funding_rate_response import FundingRateResponse
|
47
|
+
from crypticorn.klines.client.models.internal_exchange import InternalExchange
|
48
|
+
from crypticorn.klines.client.models.log_level import LogLevel
|
49
|
+
from crypticorn.klines.client.models.market_type import MarketType
|
50
|
+
from crypticorn.klines.client.models.ohlcv import OHLCV
|
43
51
|
from crypticorn.klines.client.models.resolution import Resolution
|
44
52
|
from crypticorn.klines.client.models.search_symbol import SearchSymbol
|
45
53
|
from crypticorn.klines.client.models.sort_direction import SortDirection
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# flake8: noqa
|
2
2
|
|
3
3
|
# import apis into api package
|
4
|
+
from crypticorn.klines.client.api.admin_api import AdminApi
|
4
5
|
from crypticorn.klines.client.api.change_in_timeframe_api import ChangeInTimeframeApi
|
5
6
|
from crypticorn.klines.client.api.funding_rates_api import FundingRatesApi
|
6
7
|
from crypticorn.klines.client.api.ohlcv_data_api import OHLCVDataApi
|