crypticorn 2.13.2__tar.gz → 2.14.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.
Files changed (310) hide show
  1. {crypticorn-2.13.2 → crypticorn-2.14.0}/CHANGELOG.md +26 -0
  2. {crypticorn-2.13.2/crypticorn.egg-info → crypticorn-2.14.0}/PKG-INFO +17 -9
  3. {crypticorn-2.13.2 → crypticorn-2.14.0}/README.md +16 -8
  4. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/client.py +25 -8
  5. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/errors.py +1 -1
  6. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/logging.py +2 -1
  7. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/main.py +1 -1
  8. {crypticorn-2.13.2 → crypticorn-2.14.0/crypticorn.egg-info}/PKG-INFO +17 -9
  9. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn.egg-info/SOURCES.txt +2 -3
  10. {crypticorn-2.13.2 → crypticorn-2.14.0}/pyproject.toml +1 -1
  11. crypticorn-2.14.0/tests/test_custom_session.py +113 -0
  12. crypticorn-2.13.2/tests/test_basic_client.py +0 -41
  13. crypticorn-2.13.2/tests/test_shared_aiohttp_client.py +0 -29
  14. {crypticorn-2.13.2 → crypticorn-2.14.0}/LICENSE +0 -0
  15. {crypticorn-2.13.2 → crypticorn-2.14.0}/MANIFEST.in +0 -0
  16. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/__init__.py +0 -0
  17. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/__init__.py +0 -0
  18. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/__init__.py +0 -0
  19. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api/__init__.py +0 -0
  20. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api/admin_api.py +0 -0
  21. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api/auth_api.py +0 -0
  22. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api/service_api.py +0 -0
  23. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api/user_api.py +0 -0
  24. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api/wallet_api.py +0 -0
  25. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api_client.py +0 -0
  26. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/api_response.py +0 -0
  27. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/configuration.py +0 -0
  28. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/exceptions.py +0 -0
  29. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/__init__.py +0 -0
  30. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/add_wallet200_response.py +0 -0
  31. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/add_wallet_request.py +0 -0
  32. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/authorize_user200_response.py +0 -0
  33. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/authorize_user200_response_auth.py +0 -0
  34. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/authorize_user_request.py +0 -0
  35. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/create_api_key200_response.py +0 -0
  36. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/create_api_key_request.py +0 -0
  37. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/create_user_request.py +0 -0
  38. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/get_api_keys200_response_inner.py +0 -0
  39. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response.py +0 -0
  40. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner.py +0 -0
  41. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_sale_round.py +0 -0
  42. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet.py +0 -0
  43. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet_vesting_wallets_inner.py +0 -0
  44. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response_data_inner.py +0 -0
  45. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/list_wallets200_response_user_value.py +0 -0
  46. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/logout_default_response.py +0 -0
  47. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/logout_default_response_issues_inner.py +0 -0
  48. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/oauth_callback200_response.py +0 -0
  49. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/oauth_callback200_response_user.py +0 -0
  50. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/refresh_token_info200_response.py +0 -0
  51. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/refresh_token_info200_response_user_session.py +0 -0
  52. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/resend_verification_email_request.py +0 -0
  53. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/revoke_user_tokens_request.py +0 -0
  54. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/rotate_tokens200_response.py +0 -0
  55. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/token_info200_response.py +0 -0
  56. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/unlink_wallet_request.py +0 -0
  57. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/update_user_request.py +0 -0
  58. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/user_by_username200_response.py +0 -0
  59. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/user_reset_password_request.py +0 -0
  60. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/user_set_password_request.py +0 -0
  61. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/verify200_response.py +0 -0
  62. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/verify_email200_response.py +0 -0
  63. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/verify_email200_response_auth.py +0 -0
  64. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/verify_email200_response_auth_auth.py +0 -0
  65. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/verify_email_request.py +0 -0
  66. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/verify_wallet_request.py +0 -0
  67. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/wallet_verified200_response.py +0 -0
  68. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/models/whoami200_response.py +0 -0
  69. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/py.typed +0 -0
  70. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/client/rest.py +0 -0
  71. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/auth/main.py +0 -0
  72. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/__init__.py +0 -0
  73. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/__main__.py +0 -0
  74. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/init.py +0 -0
  75. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/templates/Dockerfile +0 -0
  76. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/templates/__init__.py +0 -0
  77. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/templates/auth.py +0 -0
  78. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/templates/dependabot.yml +0 -0
  79. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/templates/merge-env.sh +0 -0
  80. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/templates/ruff.yml +0 -0
  81. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/cli/version.py +0 -0
  82. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/__init__.py +0 -0
  83. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/ansi_colors.py +0 -0
  84. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/auth.py +0 -0
  85. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/decorators.py +0 -0
  86. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/enums.py +0 -0
  87. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/exceptions.py +0 -0
  88. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/middleware.py +0 -0
  89. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/mixins.py +0 -0
  90. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/openapi.py +0 -0
  91. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/pagination.py +0 -0
  92. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/router/admin_router.py +0 -0
  93. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/router/status_router.py +0 -0
  94. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/scopes.py +0 -0
  95. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/urls.py +0 -0
  96. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/utils.py +0 -0
  97. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/common/warnings.py +0 -0
  98. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/__init__.py +0 -0
  99. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/__init__.py +0 -0
  100. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api/__init__.py +0 -0
  101. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api/admin_api.py +0 -0
  102. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api/data_api.py +0 -0
  103. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api/models_api.py +0 -0
  104. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api/status_api.py +0 -0
  105. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api_client.py +0 -0
  106. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/api_response.py +0 -0
  107. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/configuration.py +0 -0
  108. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/exceptions.py +0 -0
  109. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/__init__.py +0 -0
  110. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/api_error_identifier.py +0 -0
  111. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/api_error_level.py +0 -0
  112. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/api_error_type.py +0 -0
  113. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/coin_info.py +0 -0
  114. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/coins.py +0 -0
  115. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/data_download_response.py +0 -0
  116. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/data_info.py +0 -0
  117. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/data_options.py +0 -0
  118. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/data_version.py +0 -0
  119. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/data_version_info.py +0 -0
  120. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/download_links.py +0 -0
  121. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/evaluation.py +0 -0
  122. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/evaluation_response.py +0 -0
  123. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/exception_detail.py +0 -0
  124. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/feature_size.py +0 -0
  125. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/log_level.py +0 -0
  126. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/model_create.py +0 -0
  127. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/model_read.py +0 -0
  128. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/model_status.py +0 -0
  129. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/model_update.py +0 -0
  130. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/target.py +0 -0
  131. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/target_info.py +0 -0
  132. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/models/target_type.py +0 -0
  133. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/py.typed +0 -0
  134. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/client/rest.py +0 -0
  135. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/main.py +0 -0
  136. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/hive/utils.py +0 -0
  137. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/__init__.py +0 -0
  138. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/__init__.py +0 -0
  139. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/__init__.py +0 -0
  140. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/admin_api.py +0 -0
  141. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/change_in_timeframe_api.py +0 -0
  142. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/funding_rates_api.py +0 -0
  143. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/ohlcv_data_api.py +0 -0
  144. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/status_api.py +0 -0
  145. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/symbols_api.py +0 -0
  146. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api/udf_api.py +0 -0
  147. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api_client.py +0 -0
  148. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/api_response.py +0 -0
  149. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/configuration.py +0 -0
  150. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/exceptions.py +0 -0
  151. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/__init__.py +0 -0
  152. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/api_error_identifier.py +0 -0
  153. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/api_error_level.py +0 -0
  154. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/api_error_type.py +0 -0
  155. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/change_in_timeframe.py +0 -0
  156. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/exception_detail.py +0 -0
  157. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/funding_rate.py +0 -0
  158. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/funding_rate_response.py +0 -0
  159. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/internal_exchange.py +0 -0
  160. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/log_level.py +0 -0
  161. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/market_type.py +0 -0
  162. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/ohlcv.py +0 -0
  163. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/resolution.py +0 -0
  164. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/search_symbol.py +0 -0
  165. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/sort_direction.py +0 -0
  166. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/symbol_group.py +0 -0
  167. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/symbol_info.py +0 -0
  168. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/symbol_type.py +0 -0
  169. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/timeframe.py +0 -0
  170. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/models/udf_config.py +0 -0
  171. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/py.typed +0 -0
  172. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/client/rest.py +0 -0
  173. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/klines/main.py +0 -0
  174. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/__init__.py +0 -0
  175. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/__init__.py +0 -0
  176. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/__init__.py +0 -0
  177. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/admin_api.py +0 -0
  178. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/exchanges_api.py +0 -0
  179. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/indicators_api.py +0 -0
  180. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/logs_api.py +0 -0
  181. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/marketcap_api.py +0 -0
  182. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/markets_api.py +0 -0
  183. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/quote_currencies_api.py +0 -0
  184. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/status_api.py +0 -0
  185. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api/tokens_api.py +0 -0
  186. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api_client.py +0 -0
  187. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/api_response.py +0 -0
  188. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/configuration.py +0 -0
  189. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/exceptions.py +0 -0
  190. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/__init__.py +0 -0
  191. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/api_error_identifier.py +0 -0
  192. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/api_error_level.py +0 -0
  193. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/api_error_type.py +0 -0
  194. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/exception_detail.py +0 -0
  195. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/exchange_availability.py +0 -0
  196. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/exchange_mapping.py +0 -0
  197. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/internal_exchange.py +0 -0
  198. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/log_level.py +0 -0
  199. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/market_type.py +0 -0
  200. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/marketcap_ranking.py +0 -0
  201. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/marketcap_symbol_ranking.py +0 -0
  202. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/ohlcv.py +0 -0
  203. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/severity.py +0 -0
  204. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/time_interval.py +0 -0
  205. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/models/trading_status.py +0 -0
  206. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/py.typed +0 -0
  207. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/client/rest.py +0 -0
  208. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/metrics/main.py +0 -0
  209. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/__init__.py +0 -0
  210. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/__init__.py +0 -0
  211. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api/__init__.py +0 -0
  212. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api/admin_api.py +0 -0
  213. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api/now_payments_api.py +0 -0
  214. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api/payments_api.py +0 -0
  215. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api/products_api.py +0 -0
  216. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api/status_api.py +0 -0
  217. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api_client.py +0 -0
  218. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/api_response.py +0 -0
  219. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/configuration.py +0 -0
  220. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/exceptions.py +0 -0
  221. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/__init__.py +0 -0
  222. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/api_error_identifier.py +0 -0
  223. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/api_error_level.py +0 -0
  224. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/api_error_type.py +0 -0
  225. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/exception_detail.py +0 -0
  226. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/log_level.py +0 -0
  227. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/now_create_invoice_req.py +0 -0
  228. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/now_create_invoice_res.py +0 -0
  229. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/payment.py +0 -0
  230. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/payment_status.py +0 -0
  231. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/product.py +0 -0
  232. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/product_create.py +0 -0
  233. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/product_update.py +0 -0
  234. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/provider.py +0 -0
  235. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/scope.py +0 -0
  236. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/models/subscription.py +0 -0
  237. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/py.typed +0 -0
  238. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/client/rest.py +0 -0
  239. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/pay/main.py +0 -0
  240. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/__init__.py +0 -0
  241. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/__init__.py +0 -0
  242. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/__init__.py +0 -0
  243. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/admin_api.py +0 -0
  244. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/api_keys_api.py +0 -0
  245. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/bots_api.py +0 -0
  246. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/exchanges_api.py +0 -0
  247. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/futures_trading_panel_api.py +0 -0
  248. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/notifications_api.py +0 -0
  249. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/orders_api.py +0 -0
  250. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/status_api.py +0 -0
  251. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/strategies_api.py +0 -0
  252. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api/trading_actions_api.py +0 -0
  253. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api_client.py +0 -0
  254. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/api_response.py +0 -0
  255. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/configuration.py +0 -0
  256. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/exceptions.py +0 -0
  257. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/__init__.py +0 -0
  258. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/api_error_identifier.py +0 -0
  259. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/api_error_level.py +0 -0
  260. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/api_error_type.py +0 -0
  261. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/bot.py +0 -0
  262. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/bot_create.py +0 -0
  263. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/bot_status.py +0 -0
  264. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/bot_update.py +0 -0
  265. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/exception_detail.py +0 -0
  266. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/exchange.py +0 -0
  267. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/exchange_key.py +0 -0
  268. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/exchange_key_create.py +0 -0
  269. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/exchange_key_update.py +0 -0
  270. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/execution_ids.py +0 -0
  271. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/futures_balance.py +0 -0
  272. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/futures_trading_action.py +0 -0
  273. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/futures_trading_action_create.py +0 -0
  274. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/log_level.py +0 -0
  275. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/margin_mode.py +0 -0
  276. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/market_type.py +0 -0
  277. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/notification.py +0 -0
  278. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/notification_create.py +0 -0
  279. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/notification_update.py +0 -0
  280. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/order.py +0 -0
  281. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/order_status.py +0 -0
  282. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/post_futures_action.py +0 -0
  283. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/spot_trading_action_create.py +0 -0
  284. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/strategy.py +0 -0
  285. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/strategy_create.py +0 -0
  286. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/strategy_exchange_info.py +0 -0
  287. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/strategy_update.py +0 -0
  288. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/tpsl.py +0 -0
  289. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/tpsl_create.py +0 -0
  290. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/models/trading_action_type.py +0 -0
  291. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/py.typed +0 -0
  292. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn/trade/client/rest.py +0 -0
  293. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn.egg-info/dependency_links.txt +0 -0
  294. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn.egg-info/entry_points.txt +0 -0
  295. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn.egg-info/requires.txt +0 -0
  296. {crypticorn-2.13.2 → crypticorn-2.14.0}/crypticorn.egg-info/top_level.txt +0 -0
  297. {crypticorn-2.13.2 → crypticorn-2.14.0}/requirements/dev.txt +0 -0
  298. {crypticorn-2.13.2 → crypticorn-2.14.0}/requirements/extra.txt +0 -0
  299. {crypticorn-2.13.2 → crypticorn-2.14.0}/requirements/main.txt +0 -0
  300. {crypticorn-2.13.2 → crypticorn-2.14.0}/requirements/test.txt +0 -0
  301. {crypticorn-2.13.2 → crypticorn-2.14.0}/setup.cfg +0 -0
  302. {crypticorn-2.13.2 → crypticorn-2.14.0}/static/favicon.svg +0 -0
  303. {crypticorn-2.13.2 → crypticorn-2.14.0}/static/logo.svg +0 -0
  304. {crypticorn-2.13.2 → crypticorn-2.14.0}/static/pip-structure.drawio +0 -0
  305. {crypticorn-2.13.2 → crypticorn-2.14.0}/static/pip-structure.svg +0 -0
  306. {crypticorn-2.13.2 → crypticorn-2.14.0}/tests/test_auth_client.py +0 -0
  307. {crypticorn-2.13.2 → crypticorn-2.14.0}/tests/test_config.py +0 -0
  308. {crypticorn-2.13.2 → crypticorn-2.14.0}/tests/test_enums.py +0 -0
  309. {crypticorn-2.13.2 → crypticorn-2.14.0}/tests/test_errors.py +0 -0
  310. {crypticorn-2.13.2 → crypticorn-2.14.0}/tests/test_pagination.py +0 -0
@@ -1,6 +1,32 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v2.14.0 (2025-05-26)
5
+
6
+ ### Bug Fixes
7
+
8
+ - Fixes error code value
9
+ ([`182d4d7`](https://github.com/crypticorn-ai/api-client/commit/182d4d7a92289b66914816a90e707739dba4af1c))
10
+
11
+ ### Continuous Integration
12
+
13
+ - Cleanup on failure in release step
14
+ ([`dff5ee4`](https://github.com/crypticorn-ai/api-client/commit/dff5ee4b25832ed8b6944213325e7a6d658a2491))
15
+
16
+ ### Features
17
+
18
+ - Allow custom http client injection
19
+ ([`1a4cd0c`](https://github.com/crypticorn-ai/api-client/commit/1a4cd0cdd68d39a950f547d22721409e022c896a))
20
+
21
+
22
+ ## v2.13.3 (2025-05-26)
23
+
24
+ ### Bug Fixes
25
+
26
+ - Fixes logging import error
27
+ ([`5df42ef`](https://github.com/crypticorn-ai/api-client/commit/5df42ef9835a397ed6162dcb1c1ad4ab67badd4e))
28
+
29
+
4
30
  ## v2.13.2 (2025-05-26)
5
31
 
6
32
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.13.2
3
+ Version: 2.14.0
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License-Expression: MIT
@@ -207,19 +207,27 @@ async with ApiClient() as client:
207
207
 
208
208
  ### Session Management
209
209
 
210
- By default `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers. You can pass your own configured `aiohttp.ClientSession` for advanced use cases (for custom retry, logging, or mocking):
210
+ By default, `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers.
211
+ However, you can pass your own pre-configured `aiohttp.ClientSession` if you need advanced control — for example, to add retries, custom headers, logging, or mocking behavior.
212
+
213
+ When you inject a custom session, you are responsible for managing its lifecycle, including closing when you're done.
211
214
 
212
215
  ```python
213
216
  import aiohttp
214
217
  from crypticorn import ApiClient
215
218
 
216
- custom_http_client = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10), headers={"X-Test": "1"})
217
- api = ApiClient(api_key="your-key")
218
- api._http_client = custom_http_client
219
-
220
- for service in api._services.values():
221
- service.base_client.rest_client.pool_manager = custom_http_client
222
- ```
219
+ async def main():
220
+ custom_session = aiohttp.ClientSession()
221
+ async with ApiClient(api_key="your-key", http_client=custom_session) as client:
222
+ await client.trade.status.ping()
223
+ await custom_session.close()
224
+ # or
225
+ custom_session = aiohttp.ClientSession()
226
+ client = ApiClient(api_key="your-key", http_client=custom_session)
227
+ await client.trade.status.ping()
228
+ await custom_session.close()
229
+ ```
230
+ If you don’t pass a session, `ApiClient` will create and manage one internally. In that case, it will be automatically closed when using `async with` or when calling `await client.close()` manually.
223
231
 
224
232
  ### Disable Logging
225
233
 
@@ -152,19 +152,27 @@ async with ApiClient() as client:
152
152
 
153
153
  ### Session Management
154
154
 
155
- By default `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers. You can pass your own configured `aiohttp.ClientSession` for advanced use cases (for custom retry, logging, or mocking):
155
+ By default, `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers.
156
+ However, you can pass your own pre-configured `aiohttp.ClientSession` if you need advanced control — for example, to add retries, custom headers, logging, or mocking behavior.
157
+
158
+ When you inject a custom session, you are responsible for managing its lifecycle, including closing when you're done.
156
159
 
157
160
  ```python
158
161
  import aiohttp
159
162
  from crypticorn import ApiClient
160
163
 
161
- custom_http_client = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10), headers={"X-Test": "1"})
162
- api = ApiClient(api_key="your-key")
163
- api._http_client = custom_http_client
164
-
165
- for service in api._services.values():
166
- service.base_client.rest_client.pool_manager = custom_http_client
167
- ```
164
+ async def main():
165
+ custom_session = aiohttp.ClientSession()
166
+ async with ApiClient(api_key="your-key", http_client=custom_session) as client:
167
+ await client.trade.status.ping()
168
+ await custom_session.close()
169
+ # or
170
+ custom_session = aiohttp.ClientSession()
171
+ client = ApiClient(api_key="your-key", http_client=custom_session)
172
+ await client.trade.status.ping()
173
+ await custom_session.close()
174
+ ```
175
+ If you don’t pass a session, `ApiClient` will create and manage one internally. In that case, it will be automatically closed when using `async with` or when calling `await client.close()` manually.
168
176
 
169
177
  ### Disable Logging
170
178
 
@@ -24,6 +24,8 @@ class ApiClient:
24
24
  api_key: Optional[str] = None,
25
25
  jwt: Optional[str] = None,
26
26
  base_url: BaseUrl = BaseUrl.PROD,
27
+ *,
28
+ http_client: Optional[ClientSession] = None,
27
29
  ):
28
30
  self.base_url = base_url
29
31
  """The base URL the client will use to connect to the API."""
@@ -34,13 +36,8 @@ class ApiClient:
34
36
  self.version = version("crypticorn")
35
37
  """The version of the client."""
36
38
 
37
- # self._http_client = ClientSession(
38
- # timeout=ClientTimeout(total=30.0),
39
- # connector=TCPConnector(limit=100, limit_per_host=20),
40
- # headers={"User-Agent": f"crypticorn/python/{self.version}"},
41
- # )
42
- self._http_client = None # temporary fix for the issue with the event loop
43
-
39
+ self._http_client = http_client
40
+ self._owns_http_client = http_client is None # whether we own the http client
44
41
  self._service_classes: dict[Service, type[SubClient]] = {
45
42
  Service.HIVE: HiveClient,
46
43
  Service.TRADE: TradeClient,
@@ -99,9 +96,28 @@ class ApiClient:
99
96
  return self._services[Service.AUTH]
100
97
 
101
98
  async def close(self):
99
+ # close each in sync
102
100
  for service in self._services.values():
103
- if hasattr(service.base_client, "close"):
101
+ if hasattr(service.base_client, "close") and self._owns_http_client:
104
102
  await service.base_client.close()
103
+ # close shared in async
104
+ if self._http_client and self._owns_http_client:
105
+ await self._http_client.close()
106
+ self._http_client = None
107
+
108
+ async def _ensure_session(self) -> None:
109
+ """
110
+ Lazily create the shared HTTP client when first needed and pass it to all subclients.
111
+ """
112
+ if self._http_client is None:
113
+ self._http_client = ClientSession(
114
+ timeout=ClientTimeout(total=30.0),
115
+ connector=TCPConnector(limit=100, limit_per_host=20),
116
+ headers={"User-Agent": f"crypticorn/python/{self.version}"},
117
+ )
118
+ for service in self._services.values():
119
+ if hasattr(service, 'base_client') and hasattr(service.base_client, 'rest_client'):
120
+ service.base_client.rest_client.pool_manager = self._http_client
105
121
 
106
122
  def _get_default_config(self, service, version=None):
107
123
  if version is None:
@@ -137,6 +153,7 @@ class ApiClient:
137
153
  )
138
154
 
139
155
  async def __aenter__(self):
156
+ await self._ensure_session()
140
157
  return self
141
158
 
142
159
  async def __aexit__(self, exc_type, exc_val, exc_tb):
@@ -63,7 +63,7 @@ class ApiErrorIdentifier(StrEnum):
63
63
  EXCHANGE_USER_FROZEN = "exchange_user_account_is_frozen"
64
64
  EXPIRED_API_KEY = "api_key_expired"
65
65
  EXPIRED_BEARER = "bearer_token_expired"
66
- FAILED_OPEN_ORDER = "open_order_expired"
66
+ FAILED_OPEN_ORDER = "failed_open_order"
67
67
  FORBIDDEN = "forbidden"
68
68
  HEDGE_MODE_NOT_ACTIVE = "hedge_mode_not_active"
69
69
  INSUFFICIENT_BALANCE = "insufficient_balance"
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ from logging.handlers import RotatingFileHandler
4
5
  import sys
5
6
  from crypticorn.common.mixins import ValidateEnumMixin
6
7
  from crypticorn.common.ansi_colors import AnsiColors as C
@@ -109,7 +110,7 @@ def configure_logging(
109
110
  # Configure file handler
110
111
  if log_file:
111
112
  os.makedirs(os.path.dirname(log_file), exist_ok=True)
112
- file_handler = logging.handlers.RotatingFileHandler(
113
+ file_handler = RotatingFileHandler(
113
114
  log_file, maxBytes=10 * 1024 * 1024, backupCount=5
114
115
  )
115
116
  file_handler.setLevel(file_level)
@@ -1,5 +1,5 @@
1
1
  from __future__ import annotations
2
- from typing import TYPE_CHECKING
2
+ from typing import TYPE_CHECKING, Optional
3
3
  from crypticorn.trade import (
4
4
  ApiClient,
5
5
  APIKeysApi,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.13.2
3
+ Version: 2.14.0
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License-Expression: MIT
@@ -207,19 +207,27 @@ async with ApiClient() as client:
207
207
 
208
208
  ### Session Management
209
209
 
210
- By default `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers. You can pass your own configured `aiohttp.ClientSession` for advanced use cases (for custom retry, logging, or mocking):
210
+ By default, `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers.
211
+ However, you can pass your own pre-configured `aiohttp.ClientSession` if you need advanced control — for example, to add retries, custom headers, logging, or mocking behavior.
212
+
213
+ When you inject a custom session, you are responsible for managing its lifecycle, including closing when you're done.
211
214
 
212
215
  ```python
213
216
  import aiohttp
214
217
  from crypticorn import ApiClient
215
218
 
216
- custom_http_client = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10), headers={"X-Test": "1"})
217
- api = ApiClient(api_key="your-key")
218
- api._http_client = custom_http_client
219
-
220
- for service in api._services.values():
221
- service.base_client.rest_client.pool_manager = custom_http_client
222
- ```
219
+ async def main():
220
+ custom_session = aiohttp.ClientSession()
221
+ async with ApiClient(api_key="your-key", http_client=custom_session) as client:
222
+ await client.trade.status.ping()
223
+ await custom_session.close()
224
+ # or
225
+ custom_session = aiohttp.ClientSession()
226
+ client = ApiClient(api_key="your-key", http_client=custom_session)
227
+ await client.trade.status.ping()
228
+ await custom_session.close()
229
+ ```
230
+ If you don’t pass a session, `ApiClient` will create and manage one internally. In that case, it will be automatically closed when using `async with` or when calling `await client.close()` manually.
223
231
 
224
232
  ### Disable Logging
225
233
 
@@ -299,9 +299,8 @@ static/logo.svg
299
299
  static/pip-structure.drawio
300
300
  static/pip-structure.svg
301
301
  tests/test_auth_client.py
302
- tests/test_basic_client.py
303
302
  tests/test_config.py
303
+ tests/test_custom_session.py
304
304
  tests/test_enums.py
305
305
  tests/test_errors.py
306
- tests/test_pagination.py
307
- tests/test_shared_aiohttp_client.py
306
+ tests/test_pagination.py
@@ -5,7 +5,7 @@ readme = "README.md"
5
5
  license = "MIT"
6
6
  requires-python = ">=3.9"
7
7
  authors = [{name = "Crypticorn", email = "timon@crypticorn.com"}]
8
- version = "2.13.2"
8
+ version = "2.14.0"
9
9
  keywords = ["machine learning", "data science", "crypto", "modelling"]
10
10
  dynamic = ["dependencies", "optional-dependencies"]
11
11
 
@@ -0,0 +1,113 @@
1
+ import gc
2
+ import warnings
3
+ import pytest
4
+ import asyncio
5
+ from aiohttp import ClientSession
6
+ from crypticorn.client import ApiClient, Service # Adjust import to your path
7
+
8
+
9
+ @pytest.mark.asyncio
10
+ async def test_custom_http_client_injection():
11
+ custom_session = ClientSession()
12
+
13
+ client = ApiClient(http_client=custom_session)
14
+
15
+ # Subclients should have received the custom session immediately (sync context)
16
+ for service in Service:
17
+ subclient = client._services[service]
18
+ assert subclient.base_client.rest_client.pool_manager is custom_session
19
+
20
+ await client.close()
21
+ assert not custom_session.closed # Client did not own it
22
+
23
+ await custom_session.close()
24
+
25
+
26
+ @pytest.mark.asyncio
27
+ async def test_lazy_http_client_creation():
28
+ client = ApiClient()
29
+ assert client._http_client is None
30
+
31
+ await client._ensure_session()
32
+
33
+ assert isinstance(client._http_client, ClientSession)
34
+ for service in Service:
35
+ subclient = client._services[service]
36
+ assert subclient.base_client.rest_client.pool_manager is client._http_client
37
+
38
+ await client.close()
39
+ assert client._http_client is None # It should have been closed
40
+
41
+
42
+ @pytest.mark.asyncio
43
+ async def test_close_custom_http_client_not_owned():
44
+ custom_session = ClientSession()
45
+ client = ApiClient(http_client=custom_session)
46
+
47
+ await client.close()
48
+ assert not custom_session.closed # Still open since it wasn't owned by us
49
+
50
+ await custom_session.close()
51
+
52
+
53
+ @pytest.mark.asyncio
54
+ async def test_close_owned_http_client():
55
+ client = ApiClient()
56
+ await client._ensure_session()
57
+ session = client._http_client
58
+
59
+ await client.close()
60
+ assert session.closed # session should be closed since we own it
61
+
62
+ @pytest.mark.asyncio
63
+ async def test_unclosed_owned_session_warns():
64
+ with warnings.catch_warnings(record=True) as w:
65
+ warnings.simplefilter("always") # Catch all warnings
66
+
67
+ client = ApiClient()
68
+ await client.trade.status.ping()
69
+
70
+ # Intentionally forget to close
71
+ del client
72
+ await asyncio.sleep(0.1) # Let __del__ run
73
+
74
+ # Look for aiohttp's unclosed session warning
75
+ unclosed_warnings = [
76
+ warn for warn in w if "Unclosed client session" in str(warn.message)
77
+ ]
78
+ assert unclosed_warnings, "Expected unclosed client session warning"
79
+
80
+ @pytest.mark.asyncio
81
+ async def test_custom_session_not_closed_by_client():
82
+ with warnings.catch_warnings(record=True) as w:
83
+ warnings.simplefilter("always")
84
+ custom_session = ClientSession()
85
+ client = ApiClient(http_client=custom_session)
86
+ await client.trade.status.ping()
87
+
88
+ # Don't close the custom session
89
+ del client
90
+ del custom_session
91
+
92
+ # Force cleanup (otherwise it's unpredicatable when the warning will be raised)
93
+ await asyncio.sleep(0.1)
94
+ gc.collect()
95
+ await asyncio.sleep(0.1)
96
+
97
+ unclosed_warnings = [
98
+ warn for warn in w
99
+ if "Unclosed client session" in str(warn.message) or
100
+ "Unclosed connector" in str(warn.message)
101
+ ]
102
+ assert unclosed_warnings, "Expected unclosed client session warning"
103
+
104
+ @pytest.mark.asyncio
105
+ async def test_context_manager_usage():
106
+ async with ApiClient() as client:
107
+ assert isinstance(client._http_client, ClientSession)
108
+ for service in Service:
109
+ subclient = client._services[service]
110
+ assert subclient.base_client.rest_client.pool_manager is client._http_client
111
+
112
+ # Confirm session is closed after context manager
113
+ assert client._http_client is None
@@ -1,41 +0,0 @@
1
- import pytest
2
- import aiohttp
3
- from crypticorn import ApiClient
4
-
5
-
6
- @pytest.mark.asyncio
7
- @pytest.mark.skip(reason="temporary fix for the issue with the event loop")
8
- async def test_api_client_creation():
9
- api = ApiClient(api_key="test", jwt="test", base_url="http://localhost:8000")
10
-
11
- assert isinstance(api._http_client, aiohttp.ClientSession)
12
-
13
- for service_name, service in api._services.items():
14
- assert hasattr(service, "base_client")
15
- assert hasattr(service.base_client, "rest_client")
16
- assert service.base_client.rest_client.pool_manager is api._http_client
17
-
18
- await api.close()
19
-
20
-
21
- @pytest.mark.asyncio
22
- @pytest.mark.skip(reason="temporary fix for the issue with the event loop")
23
- async def test_custom_http_client():
24
- custom_session = aiohttp.ClientSession()
25
- custom_session.is_custom = True # Add a marker
26
-
27
- api = ApiClient(api_key="test", jwt="test", base_url="http://localhost:8000")
28
- api._http_client = custom_session
29
-
30
- for service_name, service in api._services.items():
31
- service.base_client.rest_client.pool_manager = custom_session
32
-
33
- assert api._http_client is custom_session
34
- assert hasattr(api._http_client, "is_custom")
35
-
36
- for service_name, service in api._services.items():
37
- assert service.base_client.rest_client.pool_manager is custom_session
38
- assert hasattr(service.base_client.rest_client.pool_manager, "is_custom")
39
-
40
- await api.close()
41
- await custom_session.close()
@@ -1,29 +0,0 @@
1
- import pytest
2
- import aiohttp
3
- from crypticorn import ApiClient
4
- from crypticorn.common import Service
5
-
6
-
7
- class DummyClientSession(aiohttp.ClientSession):
8
- def __init__(self, *args, **kwargs):
9
- super().__init__(*args, **kwargs)
10
- self.is_dummy = True
11
-
12
-
13
- @pytest.mark.skip(reason="temporary fix for the issue with the event loop")
14
- @pytest.mark.asyncio
15
- async def test_shared_aiohttp_client_across_services():
16
- dummy_client = DummyClientSession()
17
- api = ApiClient(api_key="test", jwt="test", base_url="http://localhost:8000")
18
- api._http_client = dummy_client
19
- for service in api._services.values():
20
- service.base_client.rest_client.pool_manager = dummy_client
21
- assert api._http_client is dummy_client
22
- assert api.hive.base_client.rest_client.pool_manager is dummy_client
23
- assert api.trade.base_client.rest_client.pool_manager is dummy_client
24
- assert api.klines.base_client.rest_client.pool_manager is dummy_client
25
- assert api.pay.base_client.rest_client.pool_manager is dummy_client
26
- assert api.metrics.base_client.rest_client.pool_manager is dummy_client
27
- assert api.auth.base_client.rest_client.pool_manager is dummy_client
28
- await api.close()
29
- await dummy_client.close()
File without changes
File without changes