crypticorn 2.8.1__tar.gz → 2.9.0__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-2.8.1 → crypticorn-2.9.0}/CHANGELOG.md +45 -0
- {crypticorn-2.8.1/crypticorn.egg-info → crypticorn-2.9.0}/PKG-INFO +2 -1
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/__init__.py +4 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/__init__.py +2 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/ansi_colors.py +2 -1
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/auth.py +2 -2
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/enums.py +2 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/errors.py +8 -5
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/exceptions.py +23 -20
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/logging.py +6 -8
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/middleware.py +2 -1
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/mixins.py +10 -3
- crypticorn-2.9.0/crypticorn/common/openapi.py +11 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/pagination.py +2 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/router/admin_router.py +12 -5
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/router/status_router.py +8 -1
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/scopes.py +3 -3
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/urls.py +9 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/utils.py +16 -8
- crypticorn-2.9.0/crypticorn/common/warnings.py +63 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/admin_api.py +22 -19
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/status_api.py +6 -6
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/configuration.py +4 -2
- {crypticorn-2.8.1 → crypticorn-2.9.0/crypticorn.egg-info}/PKG-INFO +2 -1
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn.egg-info/SOURCES.txt +2 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn.egg-info/requires.txt +1 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/pyproject.toml +1 -1
- {crypticorn-2.8.1 → crypticorn-2.9.0}/requirements/dev.txt +1 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/MANIFEST.in +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/README.md +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api/admin_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api/auth_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api/service_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api/user_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api/wallet_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/api_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/configuration.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/exceptions.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/add_wallet200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/add_wallet_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/authorize_user200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/authorize_user200_response_auth.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/authorize_user_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/create_api_key200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/create_api_key_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/create_user_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/get_api_keys200_response_inner.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_sale_round.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet_vesting_wallets_inner.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response_data_inner.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/list_wallets200_response_user_value.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/logout_default_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/logout_default_response_issues_inner.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/oauth_callback200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/oauth_callback200_response_user.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/refresh_token_info200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/refresh_token_info200_response_user_session.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/resend_verification_email_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/revoke_user_tokens_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/rotate_tokens200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/token_info200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/unlink_wallet_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/update_user_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/user_by_username200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/user_reset_password_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/user_set_password_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/verify200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/verify_email200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/verify_email200_response_auth.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/verify_email200_response_auth_auth.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/verify_email_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/verify_wallet_request.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/wallet_verified200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/models/whoami200_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/py.typed +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/client/rest.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/auth/main.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/__main__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/init.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/templates/Dockerfile +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/templates/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/templates/auth.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/templates/dependabot.yml +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/cli/templates/ruff.yml +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/common/decorators.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api/admin_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api/data_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api/models_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api/status_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/api_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/configuration.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/exceptions.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/api_error_identifier.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/api_error_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/api_error_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/coins.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/data_download_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/data_info.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/data_options.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/data_version.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/data_version_info.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/download_links.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/evaluation.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/evaluation_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/exception_detail.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/feature_size.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/log_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/model.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/model_create.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/model_status.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/model_update.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/target.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/target_info.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/models/target_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/py.typed +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/client/rest.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/main.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/hive/utils.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/admin_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/change_in_timeframe_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/funding_rates_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/ohlcv_data_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/status_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/symbols_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api/udf_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/api_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/configuration.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/exceptions.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/api_error_identifier.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/api_error_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/api_error_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/change_in_timeframe.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/exception_detail.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/funding_rate.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/funding_rate_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/internal_exchange.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/log_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/market_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/ohlcv.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/resolution.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/search_symbol.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/sort_direction.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/symbol_group.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/symbol_info.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/symbol_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/timeframe.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/models/udf_config.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/py.typed +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/client/rest.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/klines/main.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/exchanges_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/indicators_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/logs_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/marketcap_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/markets_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/quote_currencies_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api/tokens_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/api_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/exceptions.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/api_error_identifier.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/api_error_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/api_error_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/exception_detail.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/exchange_mapping.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/internal_exchange.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/log_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/market_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/marketcap_ranking.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/ohlcv.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/severity.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/time_interval.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/models/trading_status.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/py.typed +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/client/rest.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/metrics/main.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api/admin_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api/now_payments_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api/payments_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api/products_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api/status_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/api_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/configuration.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/exceptions.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/exception_detail.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/log_level.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/now_create_invoice_req.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/now_create_invoice_res.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/payment.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/payment_status.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/product_create.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/product_read.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/product_sub_read.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/product_update.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/provider.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/response_getuptime.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/models/scope.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/py.typed +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/client/rest.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/pay/main.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/api_keys_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/bots_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/exchanges_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/futures_trading_panel_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/notifications_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/orders_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/status_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/strategies_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api/trading_actions_api.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/api_response.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/configuration.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/exceptions.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/__init__.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/action_model.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/bot_model.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/bot_status.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/exception_detail.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/exchange_key_model.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/execution_ids.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/futures_balance.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/futures_trading_action.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/margin_mode.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/notification_model.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/order_model.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/order_status.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/post_futures_action.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/spot_trading_action.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/strategy_exchange_info.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/strategy_model_input.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/strategy_model_output.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/tpsl.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/models/trading_action_type.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/py.typed +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/client/rest.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn/trade/main.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn.egg-info/dependency_links.txt +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn.egg-info/entry_points.txt +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/crypticorn.egg-info/top_level.txt +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/requirements/extra.txt +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/requirements/main.txt +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/requirements/test.txt +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/setup.cfg +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/tests/test_auth_client.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/tests/test_config.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/tests/test_enums.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/tests/test_errors.py +0 -0
- {crypticorn-2.8.1 → crypticorn-2.9.0}/tests/test_pagination.py +0 -0
@@ -1,6 +1,51 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v2.9.0 (2025-05-08)
|
5
|
+
|
6
|
+
### Build System
|
7
|
+
|
8
|
+
- Add python-semantic-release as an dev dependency
|
9
|
+
([`72dfc09`](https://github.com/crypticorn-ai/api-client/commit/72dfc092b7b4fde231e6c62d3bcca33ec270bf30))
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
- Use regex pattern in /dependencies endpoint
|
14
|
+
([`7a7792f`](https://github.com/crypticorn-ai/api-client/commit/7a7792f33460b5fe4404d6f46ab680cca204a8f5))
|
15
|
+
|
16
|
+
|
17
|
+
## v2.9.0-rc.1 (2025-05-08)
|
18
|
+
|
19
|
+
### Bug Fixes
|
20
|
+
|
21
|
+
- Capture and format warnings in logging output
|
22
|
+
([`5a1d317`](https://github.com/crypticorn-ai/api-client/commit/5a1d31721507dae015e9d9568579e91b12906ee4))
|
23
|
+
|
24
|
+
- Use `contextlib.asynccontextmanager` for starlette lifespan
|
25
|
+
([`c253dd1`](https://github.com/crypticorn-ai/api-client/commit/c253dd133dff5073f355ed8f93c0be1814b739f2))
|
26
|
+
|
27
|
+
### Documentation
|
28
|
+
|
29
|
+
- Update docstrings and module descriptions
|
30
|
+
([`c80f306`](https://github.com/crypticorn-ai/api-client/commit/c80f30614641f09366ca3566295e9bce8eee828d))
|
31
|
+
|
32
|
+
### Features
|
33
|
+
|
34
|
+
- Add deprecation warnings in call and in-code support
|
35
|
+
([`b3100e6`](https://github.com/crypticorn-ai/api-client/commit/b3100e69874b8fca439778351c2834b5ae2b91b6))
|
36
|
+
|
37
|
+
- Provide default openapi tags from the status and admin router
|
38
|
+
([`e8ef966`](https://github.com/crypticorn-ai/api-client/commit/e8ef966bc9ee60a17ef8842a041d5e1800c32d93))
|
39
|
+
|
40
|
+
|
41
|
+
## v2.8.2 (2025-05-08)
|
42
|
+
|
43
|
+
### Bug Fixes
|
44
|
+
|
45
|
+
- Hotfix response type error
|
46
|
+
([`7cc14fc`](https://github.com/crypticorn-ai/api-client/commit/7cc14fcced66441d9e320ad754a164ca016cda26))
|
47
|
+
|
48
|
+
|
4
49
|
## v2.8.1 (2025-05-07)
|
5
50
|
|
6
51
|
### Bug Fixes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: crypticorn
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.9.0
|
4
4
|
Summary: Maximise Your Crypto Trading Profits with Machine Learning
|
5
5
|
Author-email: Crypticorn <timon@crypticorn.com>
|
6
6
|
License: MIT
|
@@ -43,6 +43,7 @@ Requires-Dist: isort; extra == "dev"
|
|
43
43
|
Requires-Dist: mypy; extra == "dev"
|
44
44
|
Requires-Dist: openapi-generator-cli<8.0.0,>=7.12.0; extra == "dev"
|
45
45
|
Requires-Dist: pdoc==15.0.3; extra == "dev"
|
46
|
+
Requires-Dist: python-semantic-release==9.21.0; extra == "dev"
|
46
47
|
Provides-Extra: test
|
47
48
|
Requires-Dist: pytest==8.3.5; extra == "test"
|
48
49
|
Requires-Dist: pytest-asyncio==0.26.0; extra == "test"
|
@@ -6,9 +6,13 @@ 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
|
9
11
|
from crypticorn.common.logging import configure_logging
|
10
12
|
|
13
|
+
warnings.filterwarnings("default", "", DeprecationWarning)
|
11
14
|
configure_logging()
|
15
|
+
logging.captureWarnings(True)
|
12
16
|
|
13
17
|
from crypticorn.client import ApiClient
|
14
18
|
|
@@ -11,5 +11,7 @@ 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 *
|
14
16
|
from crypticorn.common.router.status_router import router as status_router
|
15
17
|
from crypticorn.common.router.admin_router import router as admin_router
|
@@ -1,8 +1,9 @@
|
|
1
1
|
from enum import StrEnum
|
2
|
-
from typing import TYPE_CHECKING
|
3
2
|
|
4
3
|
|
5
4
|
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
|
+
|
6
7
|
# Regular Text Colors
|
7
8
|
BLACK = "\033[30m" # black
|
8
9
|
RED = "\033[31m" # red
|
@@ -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__(
|
@@ -1,10 +1,12 @@
|
|
1
|
+
"""Comprehensive error handling system defining various API error types, HTTP exceptions, and error content structures."""
|
2
|
+
|
1
3
|
from enum import Enum, StrEnum
|
2
4
|
from fastapi import status
|
3
5
|
from crypticorn.common.mixins import ExcludeEnumMixin, ApiErrorFallback
|
4
6
|
|
5
7
|
|
6
8
|
class ApiErrorType(ExcludeEnumMixin, StrEnum):
|
7
|
-
"""Type of API error"""
|
9
|
+
"""Type of the API error."""
|
8
10
|
|
9
11
|
USER_ERROR = "user error"
|
10
12
|
"""user error by people using our services"""
|
@@ -17,7 +19,7 @@ class ApiErrorType(ExcludeEnumMixin, StrEnum):
|
|
17
19
|
|
18
20
|
|
19
21
|
class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
|
20
|
-
"""API error
|
22
|
+
"""Unique identifier of the API error."""
|
21
23
|
|
22
24
|
ALLOCATION_BELOW_EXPOSURE = "allocation_below_current_exposure"
|
23
25
|
ALLOCATION_BELOW_MINIMUM = "allocation_below_min_amount"
|
@@ -103,7 +105,7 @@ class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
|
|
103
105
|
|
104
106
|
|
105
107
|
class ApiErrorLevel(ExcludeEnumMixin, StrEnum):
|
106
|
-
"""API error
|
108
|
+
"""Level of the API error."""
|
107
109
|
|
108
110
|
ERROR = "error"
|
109
111
|
INFO = "info"
|
@@ -112,7 +114,8 @@ class ApiErrorLevel(ExcludeEnumMixin, StrEnum):
|
|
112
114
|
|
113
115
|
|
114
116
|
class ApiError(ExcludeEnumMixin, Enum, metaclass=ApiErrorFallback):
|
115
|
-
|
117
|
+
# Fallback to UNKNOWN_ERROR for error codes not yet published to PyPI.
|
118
|
+
"""Crypticorn API error enumeration."""
|
116
119
|
|
117
120
|
ALLOCATION_BELOW_EXPOSURE = (
|
118
121
|
ApiErrorIdentifier.ALLOCATION_BELOW_EXPOSURE,
|
@@ -518,7 +521,7 @@ class ApiError(ExcludeEnumMixin, Enum, metaclass=ApiErrorFallback):
|
|
518
521
|
|
519
522
|
|
520
523
|
class StatusCodeMapper:
|
521
|
-
"""
|
524
|
+
"""Mapping of API errors to HTTP/Websocket status codes."""
|
522
525
|
|
523
526
|
_mapping = {
|
524
527
|
# Authentication/Authorization
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional, Dict, Any
|
1
|
+
from typing import Optional, Dict, Any
|
2
2
|
from enum import StrEnum
|
3
3
|
from pydantic import BaseModel, Field
|
4
4
|
from fastapi import HTTPException as FastAPIHTTPException, Request, FastAPI
|
@@ -8,16 +8,18 @@ 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
|
14
|
+
class _ExceptionType(StrEnum):
|
15
|
+
"""The protocol the exception is called from"""
|
16
|
+
|
15
17
|
HTTP = "http"
|
16
18
|
WEBSOCKET = "websocket"
|
17
19
|
|
18
20
|
|
19
21
|
class ExceptionDetail(BaseModel):
|
20
|
-
"""
|
22
|
+
"""Exception details returned to the client."""
|
21
23
|
|
22
24
|
message: Optional[str] = Field(None, description="An additional error message")
|
23
25
|
code: ApiErrorIdentifier = Field(..., description="The unique error code")
|
@@ -28,14 +30,14 @@ class ExceptionDetail(BaseModel):
|
|
28
30
|
|
29
31
|
|
30
32
|
class ExceptionContent(BaseModel):
|
31
|
-
"""
|
33
|
+
"""Exception content used when raising an exception."""
|
32
34
|
|
33
35
|
error: ApiError = Field(..., description="The unique error code")
|
34
36
|
message: Optional[str] = Field(None, description="An additional error message")
|
35
37
|
details: Any = Field(None, description="Additional details about the error")
|
36
38
|
|
37
39
|
def enrich(
|
38
|
-
self, _type: Optional[
|
40
|
+
self, _type: Optional[_ExceptionType] = _ExceptionType.HTTP
|
39
41
|
) -> ExceptionDetail:
|
40
42
|
return ExceptionDetail(
|
41
43
|
message=self.message,
|
@@ -44,7 +46,7 @@ class ExceptionContent(BaseModel):
|
|
44
46
|
level=self.error.level,
|
45
47
|
status_code=(
|
46
48
|
self.error.http_code
|
47
|
-
if _type ==
|
49
|
+
if _type == _ExceptionType.HTTP
|
48
50
|
else self.error.websocket_code
|
49
51
|
),
|
50
52
|
details=self.details,
|
@@ -54,14 +56,14 @@ class ExceptionContent(BaseModel):
|
|
54
56
|
class HTTPException(FastAPIHTTPException):
|
55
57
|
"""A custom HTTP exception wrapper around FastAPI's HTTPException.
|
56
58
|
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.
|
57
|
-
The ApiError class is the source of truth
|
59
|
+
The ApiError class is the source of truth. If the error is not yet implemented, there are fallbacks in place.
|
58
60
|
"""
|
59
61
|
|
60
62
|
def __init__(
|
61
63
|
self,
|
62
64
|
content: ExceptionContent,
|
63
65
|
headers: Optional[Dict[str, str]] = None,
|
64
|
-
_type: Optional[
|
66
|
+
_type: Optional[_ExceptionType] = _ExceptionType.HTTP,
|
65
67
|
):
|
66
68
|
self.content = content
|
67
69
|
self.headers = headers
|
@@ -82,11 +84,11 @@ class WebSocketException(HTTPException):
|
|
82
84
|
def __init__(
|
83
85
|
self, content: ExceptionContent, headers: Optional[Dict[str, str]] = None
|
84
86
|
):
|
85
|
-
super().__init__(content, headers, _type=
|
87
|
+
super().__init__(content, headers, _type=_ExceptionType.WEBSOCKET)
|
86
88
|
|
87
89
|
@classmethod
|
88
90
|
def from_http_exception(cls, http_exception: HTTPException):
|
89
|
-
"""
|
91
|
+
"""Helper method to convert an HTTPException to a WebSocketException."""
|
90
92
|
return WebSocketException(
|
91
93
|
content=http_exception.content,
|
92
94
|
headers=http_exception.headers,
|
@@ -94,46 +96,47 @@ class WebSocketException(HTTPException):
|
|
94
96
|
|
95
97
|
|
96
98
|
async def general_handler(request: Request, exc: Exception) -> JSONResponse:
|
97
|
-
"""
|
99
|
+
"""Default exception handler for all exceptions."""
|
98
100
|
body = ExceptionContent(message=str(exc), error=ApiError.UNKNOWN_ERROR)
|
99
101
|
res = JSONResponse(
|
100
102
|
status_code=body.enrich().status_code,
|
101
103
|
content=HTTPException(content=body).detail,
|
102
104
|
)
|
103
|
-
|
105
|
+
_logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
104
106
|
return res
|
105
107
|
|
106
108
|
|
107
109
|
async def request_validation_handler(
|
108
110
|
request: Request, exc: RequestValidationError
|
109
111
|
) -> JSONResponse:
|
110
|
-
"""
|
112
|
+
"""Exception handler for all request validation errors."""
|
111
113
|
body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_REQUEST)
|
112
114
|
res = JSONResponse(
|
113
115
|
status_code=body.enrich().status_code,
|
114
116
|
content=HTTPException(content=body).detail,
|
115
117
|
)
|
116
|
-
|
118
|
+
_logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
117
119
|
return res
|
118
120
|
|
119
121
|
|
120
122
|
async def response_validation_handler(
|
121
123
|
request: Request, exc: ResponseValidationError
|
122
124
|
) -> JSONResponse:
|
123
|
-
"""
|
125
|
+
"""Exception handler for all response validation errors."""
|
124
126
|
body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_RESPONSE)
|
125
127
|
res = JSONResponse(
|
126
128
|
status_code=body.enrich().status_code,
|
127
129
|
content=HTTPException(content=body).detail,
|
128
130
|
)
|
129
|
-
|
131
|
+
_logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
130
132
|
return res
|
131
133
|
|
132
134
|
|
133
135
|
async def http_handler(request: Request, exc: HTTPException) -> JSONResponse:
|
134
|
-
"""
|
135
|
-
|
136
|
-
|
136
|
+
"""Exception handler for HTTPExceptions. It unwraps the HTTPException and returns the detail in a flat JSON response."""
|
137
|
+
res = JSONResponse(status_code=exc.status_code, content=exc.detail)
|
138
|
+
_logger.error(f"HTTP error: {json.loads(res.__dict__.get('body'))}")
|
139
|
+
return res
|
137
140
|
|
138
141
|
|
139
142
|
def register_exception_handlers(app: FastAPI):
|
@@ -1,12 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
# shared_logger.py
|
4
3
|
import logging
|
5
4
|
import sys
|
6
|
-
from contextvars import ContextVar
|
7
|
-
from contextlib import asynccontextmanager
|
8
|
-
import json
|
9
|
-
from pydantic import BaseModel
|
10
5
|
from enum import StrEnum
|
11
6
|
from crypticorn.common.mixins import ValidateEnumMixin
|
12
7
|
from crypticorn.common.ansi_colors import AnsiColors as C
|
@@ -23,6 +18,7 @@ class LogLevel(ValidateEnumMixin, StrEnum):
|
|
23
18
|
|
24
19
|
@classmethod
|
25
20
|
def get_color(cls, level: str) -> str:
|
21
|
+
"""Get the ansi color based on the log level."""
|
26
22
|
if level == cls.DEBUG:
|
27
23
|
return C.GREEN_BRIGHT
|
28
24
|
elif level == cls.INFO:
|
@@ -38,10 +34,12 @@ class LogLevel(ValidateEnumMixin, StrEnum):
|
|
38
34
|
|
39
35
|
@staticmethod
|
40
36
|
def get_level(level: "LogLevel") -> int:
|
37
|
+
"""Get the integer value from a log level name."""
|
41
38
|
return logging._nameToLevel.get(level, logging.INFO)
|
42
39
|
|
43
40
|
@staticmethod
|
44
41
|
def get_name(level: int) -> "LogLevel":
|
42
|
+
"""Get the level name from the integer value of a log level."""
|
45
43
|
return LogLevel(logging._levelToName.get(level, "INFO"))
|
46
44
|
|
47
45
|
|
@@ -54,7 +52,7 @@ _LOGFORMAT = (
|
|
54
52
|
_DATEFMT = "%Y-%m-%d %H:%M:%S.%f:"
|
55
53
|
|
56
54
|
|
57
|
-
class
|
55
|
+
class _CustomFormatter(logging.Formatter):
|
58
56
|
def __init__(self, *args, **kwargs):
|
59
57
|
super().__init__(*args, **kwargs)
|
60
58
|
|
@@ -99,7 +97,7 @@ def configure_logging(
|
|
99
97
|
# Configure stdout handler
|
100
98
|
stdout_handler = logging.StreamHandler(sys.stdout)
|
101
99
|
stdout_handler.setLevel(stdout_level)
|
102
|
-
stdout_handler.setFormatter(
|
100
|
+
stdout_handler.setFormatter(_CustomFormatter(fmt=fmt, datefmt=datefmt))
|
103
101
|
for filter in filters:
|
104
102
|
stdout_handler.addFilter(filter)
|
105
103
|
logger.addHandler(stdout_handler)
|
@@ -111,7 +109,7 @@ def configure_logging(
|
|
111
109
|
log_file, maxBytes=10 * 1024 * 1024, backupCount=5
|
112
110
|
)
|
113
111
|
file_handler.setLevel(file_level)
|
114
|
-
file_handler.setFormatter(
|
112
|
+
file_handler.setFormatter(_CustomFormatter(fmt=fmt, datefmt=datefmt))
|
115
113
|
for filter in filters:
|
116
114
|
file_handler.addFilter(filter)
|
117
115
|
logger.addHandler(file_handler)
|
@@ -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
|
-
import
|
4
|
+
from contextlib import asynccontextmanager
|
5
5
|
|
6
6
|
|
7
7
|
def add_cors_middleware(app: "FastAPI"):
|
@@ -18,6 +18,7 @@ def add_cors_middleware(app: "FastAPI"):
|
|
18
18
|
)
|
19
19
|
|
20
20
|
|
21
|
+
@asynccontextmanager
|
21
22
|
async def default_lifespan(app: FastAPI):
|
22
23
|
"""Default lifespan for the applications.
|
23
24
|
This is used to configure the logging for the application.
|
@@ -1,7 +1,9 @@
|
|
1
1
|
from enum import EnumMeta
|
2
2
|
import logging
|
3
|
+
import warnings
|
4
|
+
from crypticorn.common.warnings import CrypticornDeprecatedSince28
|
3
5
|
|
4
|
-
|
6
|
+
_logger = logging.getLogger("crypticorn")
|
5
7
|
|
6
8
|
|
7
9
|
class ValidateEnumMixin:
|
@@ -35,7 +37,12 @@ class ValidateEnumMixin:
|
|
35
37
|
|
36
38
|
# This Mixin will be removed in a future version. And has no effect from now on
|
37
39
|
class ExcludeEnumMixin:
|
38
|
-
"""Mixin to exclude enum from OpenAPI schema. We use this to avoid duplicating enums when generating client code from the openapi spec."""
|
40
|
+
"""(deprecated) Mixin to exclude enum from OpenAPI schema. We use this to avoid duplicating enums when generating client code from the openapi spec."""
|
41
|
+
|
42
|
+
warnings.warn(
|
43
|
+
"The `ExcludeEnumMixin` class is deprecated. Should be removed from enums inheriting this class.",
|
44
|
+
category=CrypticornDeprecatedSince28,
|
45
|
+
)
|
39
46
|
|
40
47
|
@classmethod
|
41
48
|
def __get_pydantic_json_schema__(cls, core_schema, handler):
|
@@ -51,7 +58,7 @@ class ApiErrorFallback(EnumMeta):
|
|
51
58
|
# Let Pydantic/internal stuff pass silently ! fragile
|
52
59
|
if name.startswith("__"):
|
53
60
|
raise AttributeError(name)
|
54
|
-
|
61
|
+
_logger.warning(
|
55
62
|
f"Unknown enum member '{name}' - update crypticorn package or check for typos"
|
56
63
|
)
|
57
64
|
return cls.UNKNOWN_ERROR
|
@@ -10,8 +10,9 @@ import importlib.metadata
|
|
10
10
|
import threading
|
11
11
|
import time
|
12
12
|
import psutil
|
13
|
+
import re
|
13
14
|
from fastapi import APIRouter, Query
|
14
|
-
from typing import Literal
|
15
|
+
from typing import Literal
|
15
16
|
from crypticorn.common.logging import LogLevel
|
16
17
|
import logging
|
17
18
|
|
@@ -86,13 +87,19 @@ def get_container_limits() -> dict:
|
|
86
87
|
def list_installed_packages(
|
87
88
|
include: list[str] = Query(
|
88
89
|
default=None,
|
89
|
-
description="List of
|
90
|
+
description="List of regex patterns to match against package names. If not provided, all installed packages will be returned.",
|
90
91
|
)
|
91
|
-
) ->
|
92
|
-
"""Return a list of installed packages and versions.
|
92
|
+
) -> dict[str, str]:
|
93
|
+
"""Return a list of installed packages and versions.
|
94
|
+
|
95
|
+
The include parameter accepts regex patterns to match against package names.
|
96
|
+
For example:
|
97
|
+
- crypticorn.* will match all packages starting with 'crypticorn'
|
98
|
+
- .*tic.* will match all packages containing 'tic' in their name
|
99
|
+
"""
|
93
100
|
packages = {
|
94
101
|
dist.metadata["Name"]: dist.version
|
95
102
|
for dist in importlib.metadata.distributions()
|
96
|
-
if include is None or dist.metadata["Name"] in include
|
103
|
+
if include is None or any(re.match(pattern, dist.metadata["Name"]) for pattern in include)
|
97
104
|
}
|
98
105
|
return dict(sorted(packages.items()))
|
@@ -1,3 +1,10 @@
|
|
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
|
+
|
1
8
|
from datetime import datetime
|
2
9
|
from typing import Literal
|
3
10
|
from fastapi import APIRouter, Request
|
@@ -6,7 +13,7 @@ router = APIRouter(tags=["Status"], prefix="")
|
|
6
13
|
|
7
14
|
|
8
15
|
@router.get("/", operation_id="ping")
|
9
|
-
async def ping(request: Request) ->
|
16
|
+
async def ping(request: Request) -> str:
|
10
17
|
"""
|
11
18
|
Returns 'OK' if the API is running.
|
12
19
|
"""
|
@@ -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
|
]
|
@@ -3,6 +3,8 @@ 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
|
+
|
6
8
|
PROD = "prod"
|
7
9
|
DEV = "dev"
|
8
10
|
LOCAL = "local"
|
@@ -10,6 +12,8 @@ class ApiEnv(StrEnum):
|
|
10
12
|
|
11
13
|
|
12
14
|
class BaseUrl(StrEnum):
|
15
|
+
"""The base URL to connect to the API."""
|
16
|
+
|
13
17
|
PROD = "https://api.crypticorn.com"
|
14
18
|
DEV = "https://api.crypticorn.dev"
|
15
19
|
LOCAL = "http://localhost"
|
@@ -17,6 +21,7 @@ class BaseUrl(StrEnum):
|
|
17
21
|
|
18
22
|
@classmethod
|
19
23
|
def from_env(cls, env: ApiEnv) -> "BaseUrl":
|
24
|
+
"""Load the base URL from the API environment."""
|
20
25
|
if env == ApiEnv.PROD:
|
21
26
|
return cls.PROD
|
22
27
|
elif env == ApiEnv.DEV:
|
@@ -28,10 +33,14 @@ class BaseUrl(StrEnum):
|
|
28
33
|
|
29
34
|
|
30
35
|
class ApiVersion(StrEnum):
|
36
|
+
"""Versions to use for the microservice APIs."""
|
37
|
+
|
31
38
|
V1 = "v1"
|
32
39
|
|
33
40
|
|
34
41
|
class Service(ValidateEnumMixin, StrEnum):
|
42
|
+
"""The microservices available to connect to through the API"""
|
43
|
+
|
35
44
|
HIVE = "hive"
|
36
45
|
KLINES = "klines"
|
37
46
|
PAY = "pay"
|
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
"""General utility functions and helper methods used across the codebase."""
|
2
|
+
|
3
|
+
from typing import Any
|
2
4
|
from decimal import Decimal
|
3
5
|
import string
|
4
6
|
import random
|
5
|
-
|
6
|
-
|
7
|
+
import typing_extensions
|
8
|
+
import warnings
|
7
9
|
|
8
|
-
from crypticorn.common import ApiError, HTTPException, ExceptionContent
|
10
|
+
from crypticorn.common.exceptions import ApiError, HTTPException, ExceptionContent
|
11
|
+
from crypticorn.common.warnings import CrypticornDeprecatedSince25
|
9
12
|
|
10
13
|
|
11
14
|
def throw_if_none(
|
@@ -33,7 +36,9 @@ def gen_random_id(length: int = 20) -> str:
|
|
33
36
|
return "".join(random.choice(charset) for _ in range(length))
|
34
37
|
|
35
38
|
|
36
|
-
@deprecated(
|
39
|
+
@typing_extensions.deprecated(
|
40
|
+
"The `is_equal` method is deprecated; use `math.is_close` instead.", category=None
|
41
|
+
)
|
37
42
|
def is_equal(
|
38
43
|
a: float | Decimal,
|
39
44
|
b: float | Decimal,
|
@@ -43,6 +48,10 @@ def is_equal(
|
|
43
48
|
"""
|
44
49
|
Compare two Decimal numbers for approximate equality.
|
45
50
|
"""
|
51
|
+
warnings.warn(
|
52
|
+
"The `is_equal` method is deprecated; use `math.is_close` instead.",
|
53
|
+
category=CrypticornDeprecatedSince25,
|
54
|
+
)
|
46
55
|
if not isinstance(a, Decimal):
|
47
56
|
a = Decimal(str(a))
|
48
57
|
if not isinstance(b, Decimal):
|
@@ -56,13 +65,12 @@ def is_equal(
|
|
56
65
|
|
57
66
|
def optional_import(module_name: str, extra_name: str) -> Any:
|
58
67
|
"""
|
59
|
-
|
68
|
+
Tries to import a module. Raises `ImportError` if not found with a message to install the extra dependency.
|
60
69
|
"""
|
61
70
|
try:
|
62
71
|
return __import__(module_name)
|
63
72
|
except ImportError as e:
|
64
|
-
extra = f"[{extra_name}]"
|
65
73
|
raise ImportError(
|
66
74
|
f"Optional dependency '{module_name}' is required for this feature. "
|
67
|
-
f"Install it with: pip install crypticorn{
|
75
|
+
f"Install it with: pip install crypticorn[{extra_name}]"
|
68
76
|
) from e
|