ccxt 4.3.54__py2.py3-none-any.whl → 4.3.55__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/kucoin.py +3 -0
  3. ccxt/abstract/kucoinfutures.py +3 -0
  4. ccxt/ace.py +1 -1
  5. ccxt/alpaca.py +1 -1
  6. ccxt/ascendex.py +6 -4
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/ace.py +1 -1
  9. ccxt/async_support/alpaca.py +1 -1
  10. ccxt/async_support/ascendex.py +6 -4
  11. ccxt/async_support/base/exchange.py +1 -1
  12. ccxt/async_support/bigone.py +1 -1
  13. ccxt/async_support/binance.py +6 -6
  14. ccxt/async_support/bingx.py +3 -3
  15. ccxt/async_support/bit2c.py +1 -1
  16. ccxt/async_support/bitbank.py +1 -1
  17. ccxt/async_support/bitbns.py +1 -1
  18. ccxt/async_support/bitfinex.py +1 -1
  19. ccxt/async_support/bitfinex2.py +1 -1
  20. ccxt/async_support/bitflyer.py +1 -1
  21. ccxt/async_support/bitget.py +2 -2
  22. ccxt/async_support/bithumb.py +1 -1
  23. ccxt/async_support/bitmart.py +3 -3
  24. ccxt/async_support/bitmex.py +1 -1
  25. ccxt/async_support/bitopro.py +1 -1
  26. ccxt/async_support/bitrue.py +1 -1
  27. ccxt/async_support/bitso.py +1 -1
  28. ccxt/async_support/bitstamp.py +1 -1
  29. ccxt/async_support/bitteam.py +1 -1
  30. ccxt/async_support/bitvavo.py +2 -2
  31. ccxt/async_support/bl3p.py +1 -1
  32. ccxt/async_support/blockchaincom.py +28 -28
  33. ccxt/async_support/blofin.py +1 -1
  34. ccxt/async_support/btcalpha.py +4 -11
  35. ccxt/async_support/btcbox.py +1 -1
  36. ccxt/async_support/btcmarkets.py +1 -1
  37. ccxt/async_support/btcturk.py +1 -1
  38. ccxt/async_support/bybit.py +2 -2
  39. ccxt/async_support/cex.py +2 -2
  40. ccxt/async_support/coinbase.py +33 -33
  41. ccxt/async_support/coinbaseexchange.py +1 -1
  42. ccxt/async_support/coinbaseinternational.py +1 -1
  43. ccxt/async_support/coincheck.py +1 -1
  44. ccxt/async_support/coinex.py +2 -2
  45. ccxt/async_support/coinlist.py +2 -2
  46. ccxt/async_support/coinmate.py +1 -1
  47. ccxt/async_support/coinmetro.py +1 -1
  48. ccxt/async_support/coinone.py +1 -1
  49. ccxt/async_support/coinsph.py +1 -1
  50. ccxt/async_support/coinspot.py +1 -1
  51. ccxt/async_support/cryptocom.py +1 -1
  52. ccxt/async_support/currencycom.py +1 -1
  53. ccxt/async_support/delta.py +2 -2
  54. ccxt/async_support/deribit.py +4 -4
  55. ccxt/async_support/digifinex.py +2 -2
  56. ccxt/async_support/exmo.py +2 -2
  57. ccxt/async_support/gate.py +2 -2
  58. ccxt/async_support/gemini.py +1 -1
  59. ccxt/async_support/hitbtc.py +1 -1
  60. ccxt/async_support/hollaex.py +1 -1
  61. ccxt/async_support/htx.py +3 -3
  62. ccxt/async_support/huobijp.py +1 -1
  63. ccxt/async_support/hyperliquid.py +2 -2
  64. ccxt/async_support/idex.py +1 -1
  65. ccxt/async_support/independentreserve.py +1 -1
  66. ccxt/async_support/indodax.py +1 -1
  67. ccxt/async_support/kraken.py +2 -2
  68. ccxt/async_support/kucoin.py +127 -46
  69. ccxt/async_support/kucoinfutures.py +1 -1
  70. ccxt/async_support/kuna.py +1 -1
  71. ccxt/async_support/latoken.py +1 -1
  72. ccxt/async_support/lbank.py +1 -1
  73. ccxt/async_support/luno.py +1 -1
  74. ccxt/async_support/lykke.py +1 -1
  75. ccxt/async_support/mercado.py +1 -1
  76. ccxt/async_support/mexc.py +1 -1
  77. ccxt/async_support/ndax.py +1 -1
  78. ccxt/async_support/novadax.py +1 -1
  79. ccxt/async_support/oceanex.py +1 -1
  80. ccxt/async_support/okcoin.py +1 -1
  81. ccxt/async_support/okx.py +3 -3
  82. ccxt/async_support/onetrading.py +1 -1
  83. ccxt/async_support/oxfun.py +2 -2
  84. ccxt/async_support/p2b.py +1 -1
  85. ccxt/async_support/paymium.py +1 -1
  86. ccxt/async_support/phemex.py +2 -2
  87. ccxt/async_support/poloniex.py +4 -3
  88. ccxt/async_support/poloniexfutures.py +1 -1
  89. ccxt/async_support/probit.py +1 -1
  90. ccxt/async_support/timex.py +1 -1
  91. ccxt/async_support/tokocrypto.py +1 -1
  92. ccxt/async_support/tradeogre.py +1 -1
  93. ccxt/async_support/upbit.py +1 -1
  94. ccxt/async_support/vertex.py +2 -2
  95. ccxt/async_support/wavesexchange.py +1 -1
  96. ccxt/async_support/wazirx.py +1 -1
  97. ccxt/async_support/whitebit.py +2 -2
  98. ccxt/async_support/woo.py +5 -5
  99. ccxt/async_support/woofipro.py +3 -3
  100. ccxt/async_support/yobit.py +1 -1
  101. ccxt/async_support/zaif.py +1 -1
  102. ccxt/async_support/zonda.py +1 -1
  103. ccxt/base/exchange.py +1 -1
  104. ccxt/base/types.py +4 -1
  105. ccxt/bigone.py +1 -1
  106. ccxt/binance.py +6 -6
  107. ccxt/bingx.py +3 -3
  108. ccxt/bit2c.py +1 -1
  109. ccxt/bitbank.py +1 -1
  110. ccxt/bitbns.py +1 -1
  111. ccxt/bitfinex.py +1 -1
  112. ccxt/bitfinex2.py +1 -1
  113. ccxt/bitflyer.py +1 -1
  114. ccxt/bitget.py +2 -2
  115. ccxt/bithumb.py +1 -1
  116. ccxt/bitmart.py +3 -3
  117. ccxt/bitmex.py +1 -1
  118. ccxt/bitopro.py +1 -1
  119. ccxt/bitrue.py +1 -1
  120. ccxt/bitso.py +1 -1
  121. ccxt/bitstamp.py +1 -1
  122. ccxt/bitteam.py +1 -1
  123. ccxt/bitvavo.py +2 -2
  124. ccxt/bl3p.py +1 -1
  125. ccxt/blockchaincom.py +28 -28
  126. ccxt/blofin.py +1 -1
  127. ccxt/btcalpha.py +4 -11
  128. ccxt/btcbox.py +1 -1
  129. ccxt/btcmarkets.py +1 -1
  130. ccxt/btcturk.py +1 -1
  131. ccxt/bybit.py +2 -2
  132. ccxt/cex.py +2 -2
  133. ccxt/coinbase.py +33 -33
  134. ccxt/coinbaseexchange.py +1 -1
  135. ccxt/coinbaseinternational.py +1 -1
  136. ccxt/coincheck.py +1 -1
  137. ccxt/coinex.py +2 -2
  138. ccxt/coinlist.py +2 -2
  139. ccxt/coinmate.py +1 -1
  140. ccxt/coinmetro.py +1 -1
  141. ccxt/coinone.py +1 -1
  142. ccxt/coinsph.py +1 -1
  143. ccxt/coinspot.py +1 -1
  144. ccxt/cryptocom.py +1 -1
  145. ccxt/currencycom.py +1 -1
  146. ccxt/delta.py +2 -2
  147. ccxt/deribit.py +4 -4
  148. ccxt/digifinex.py +2 -2
  149. ccxt/exmo.py +2 -2
  150. ccxt/gate.py +2 -2
  151. ccxt/gemini.py +1 -1
  152. ccxt/hitbtc.py +1 -1
  153. ccxt/hollaex.py +1 -1
  154. ccxt/htx.py +3 -3
  155. ccxt/huobijp.py +1 -1
  156. ccxt/hyperliquid.py +2 -2
  157. ccxt/idex.py +1 -1
  158. ccxt/independentreserve.py +1 -1
  159. ccxt/indodax.py +1 -1
  160. ccxt/kraken.py +2 -2
  161. ccxt/kucoin.py +127 -46
  162. ccxt/kucoinfutures.py +1 -1
  163. ccxt/kuna.py +1 -1
  164. ccxt/latoken.py +1 -1
  165. ccxt/lbank.py +1 -1
  166. ccxt/luno.py +1 -1
  167. ccxt/lykke.py +1 -1
  168. ccxt/mercado.py +1 -1
  169. ccxt/mexc.py +1 -1
  170. ccxt/ndax.py +1 -1
  171. ccxt/novadax.py +1 -1
  172. ccxt/oceanex.py +1 -1
  173. ccxt/okcoin.py +1 -1
  174. ccxt/okx.py +3 -3
  175. ccxt/onetrading.py +1 -1
  176. ccxt/oxfun.py +2 -2
  177. ccxt/p2b.py +1 -1
  178. ccxt/paymium.py +1 -1
  179. ccxt/phemex.py +2 -2
  180. ccxt/poloniex.py +4 -3
  181. ccxt/poloniexfutures.py +1 -1
  182. ccxt/pro/__init__.py +1 -1
  183. ccxt/pro/binance.py +2 -2
  184. ccxt/pro/bitvavo.py +2 -2
  185. ccxt/pro/bybit.py +2 -2
  186. ccxt/pro/cex.py +3 -3
  187. ccxt/pro/coinbase.py +22 -1
  188. ccxt/pro/cryptocom.py +1 -1
  189. ccxt/pro/gate.py +2 -2
  190. ccxt/pro/hitbtc.py +1 -1
  191. ccxt/pro/kraken.py +2 -2
  192. ccxt/pro/kucoin.py +2 -2
  193. ccxt/pro/okx.py +2 -2
  194. ccxt/pro/oxfun.py +2 -2
  195. ccxt/pro/poloniex.py +1 -1
  196. ccxt/pro/vertex.py +1 -1
  197. ccxt/probit.py +1 -1
  198. ccxt/test/{test_async.py → tests_async.py} +27 -280
  199. ccxt/test/tests_helpers.py +284 -0
  200. ccxt/test/tests_init.py +35 -0
  201. ccxt/test/{test_sync.py → tests_sync.py} +27 -282
  202. ccxt/timex.py +1 -1
  203. ccxt/tokocrypto.py +1 -1
  204. ccxt/tradeogre.py +1 -1
  205. ccxt/upbit.py +1 -1
  206. ccxt/vertex.py +2 -2
  207. ccxt/wavesexchange.py +1 -1
  208. ccxt/wazirx.py +1 -1
  209. ccxt/whitebit.py +2 -2
  210. ccxt/woo.py +5 -5
  211. ccxt/woofipro.py +3 -3
  212. ccxt/yobit.py +1 -1
  213. ccxt/zaif.py +1 -1
  214. ccxt/zonda.py +1 -1
  215. {ccxt-4.3.54.dist-info → ccxt-4.3.55.dist-info}/METADATA +5 -5
  216. {ccxt-4.3.54.dist-info → ccxt-4.3.55.dist-info}/RECORD +219 -252
  217. ccxt/test/base/__init__.py +0 -29
  218. ccxt/test/base/test_account.py +0 -26
  219. ccxt/test/base/test_balance.py +0 -56
  220. ccxt/test/base/test_borrow_interest.py +0 -35
  221. ccxt/test/base/test_borrow_rate.py +0 -32
  222. ccxt/test/base/test_calculate_fee.py +0 -51
  223. ccxt/test/base/test_crypto.py +0 -127
  224. ccxt/test/base/test_currency.py +0 -76
  225. ccxt/test/base/test_datetime.py +0 -109
  226. ccxt/test/base/test_decimal_to_precision.py +0 -392
  227. ccxt/test/base/test_deep_extend.py +0 -68
  228. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  229. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  230. ccxt/test/base/test_funding_rate_history.py +0 -29
  231. ccxt/test/base/test_last_price.py +0 -31
  232. ccxt/test/base/test_ledger_entry.py +0 -45
  233. ccxt/test/base/test_ledger_item.py +0 -48
  234. ccxt/test/base/test_leverage_tier.py +0 -33
  235. ccxt/test/base/test_liquidation.py +0 -50
  236. ccxt/test/base/test_margin_mode.py +0 -24
  237. ccxt/test/base/test_margin_modification.py +0 -35
  238. ccxt/test/base/test_market.py +0 -193
  239. ccxt/test/base/test_number.py +0 -411
  240. ccxt/test/base/test_ohlcv.py +0 -33
  241. ccxt/test/base/test_open_interest.py +0 -32
  242. ccxt/test/base/test_order.py +0 -64
  243. ccxt/test/base/test_order_book.py +0 -69
  244. ccxt/test/base/test_position.py +0 -60
  245. ccxt/test/base/test_shared_methods.py +0 -353
  246. ccxt/test/base/test_status.py +0 -24
  247. ccxt/test/base/test_throttle.py +0 -126
  248. ccxt/test/base/test_ticker.py +0 -92
  249. ccxt/test/base/test_trade.py +0 -47
  250. ccxt/test/base/test_trading_fee.py +0 -26
  251. ccxt/test/base/test_transaction.py +0 -39
  252. {ccxt-4.3.54.dist-info → ccxt-4.3.55.dist-info}/LICENSE.txt +0 -0
  253. {ccxt-4.3.54.dist-info → ccxt-4.3.55.dist-info}/WHEEL +0 -0
  254. {ccxt-4.3.54.dist-info → ccxt-4.3.55.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,284 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import argparse
4
+ import json
5
+ # import logging
6
+ import os
7
+ import sys
8
+ from traceback import format_tb, format_exception
9
+
10
+ import importlib # noqa: E402
11
+ import re
12
+
13
+ # ------------------------------------------------------------------------------
14
+ # logging.basicConfig(level=logging.INFO)
15
+ # ------------------------------------------------------------------------------
16
+ DIR_NAME = os.path.dirname(os.path.abspath(__file__))
17
+ root = os.path.dirname(os.path.dirname(DIR_NAME))
18
+ sys.path.append(root)
19
+
20
+ import ccxt.async_support as ccxt # noqa: E402
21
+ import ccxt as ccxt_sync # noqa: E402
22
+ import ccxt.pro as ccxtpro # noqa: E402
23
+
24
+ # ------------------------------------------------------------------------------
25
+ # from typing import Optional
26
+ # from typing import List
27
+ from ccxt.base.errors import NotSupported # noqa: F401
28
+ from ccxt.base.errors import ProxyError # noqa: F401
29
+ from ccxt.base.errors import OperationFailed # noqa: F401
30
+ # from ccxt.base.errors import ExchangeError
31
+ from ccxt.base.errors import ExchangeNotAvailable # noqa: F401
32
+ from ccxt.base.errors import OnMaintenance # noqa: F401
33
+ from ccxt.base.errors import AuthenticationError # noqa: F401
34
+
35
+ # ------------------------------------------------------------------------------
36
+
37
+ class Argv(object):
38
+ id_tests = False
39
+ static_tests = False
40
+ ws_tests = False
41
+ request_tests = False
42
+ response_tests = False
43
+ token_bucket = False
44
+ sandbox = False
45
+ privateOnly = False
46
+ private = False
47
+ ws = False
48
+ verbose = False
49
+ nonce = None
50
+ exchange = None
51
+ symbol = None
52
+ info = False
53
+ sync = False
54
+ baseTests = False
55
+ exchangeTests = False
56
+ pass
57
+
58
+
59
+ argv = Argv()
60
+ parser = argparse.ArgumentParser()
61
+ parser.add_argument('--token_bucket', action='store_true', help='enable token bucket experimental test')
62
+ parser.add_argument('--sandbox', action='store_true', help='enable sandbox mode')
63
+ parser.add_argument('--privateOnly', action='store_true', help='run private tests only')
64
+ parser.add_argument('--private', action='store_true', help='run private tests')
65
+ parser.add_argument('--verbose', action='store_true', help='enable verbose output')
66
+ parser.add_argument('--ws', action='store_true', help='websockets version')
67
+ parser.add_argument('--info', action='store_true', help='enable info output')
68
+ parser.add_argument('--static', action='store_true', help='run static tests')
69
+ parser.add_argument('--useProxy', action='store_true', help='run static tests')
70
+ parser.add_argument('--idTests', action='store_true', help='run brokerId tests')
71
+ parser.add_argument('--responseTests', action='store_true', help='run response tests')
72
+ parser.add_argument('--requestTests', action='store_true', help='run response tests')
73
+ parser.add_argument('--sync', action='store_true', help='is sync')
74
+ parser.add_argument('--baseTests', action='store_true', help='is base tests')
75
+ parser.add_argument('--exchangeTests', action='store_true', help='is exchange tests')
76
+ parser.add_argument('--nonce', type=int, help='integer')
77
+ parser.add_argument('exchange', type=str, help='exchange id in lowercase', nargs='?')
78
+ parser.add_argument('symbol', type=str, help='symbol in uppercase', nargs='?')
79
+ parser.parse_args(namespace=argv)
80
+
81
+ # ------------------------------------------------------------------------------
82
+
83
+ path = os.path.dirname(ccxt.__file__)
84
+ if 'site-packages' in os.path.dirname(ccxt.__file__):
85
+ raise Exception("You are running tests_async.py/test.py against a globally-installed version of the library! It was previously installed into your site-packages folder by pip or pip3. To ensure testing against the local folder uninstall it first with pip uninstall ccxt or pip3 uninstall ccxt")
86
+
87
+ # ------------------------------------------------------------------------------
88
+
89
+ Error = Exception
90
+
91
+ # # print an error string
92
+ # def dump_error(*args):
93
+ # string = ' '.join([str(arg) for arg in args])
94
+ # print(string)
95
+ # sys.stderr.write(string + "\n")
96
+ # sys.stderr.flush()
97
+
98
+
99
+ def handle_all_unhandled_exceptions(type, value, traceback):
100
+ dump((type), (value), '\n<UNHANDLED EXCEPTION>\n' + ('\n'.join(format_tb(traceback))))
101
+ exit(1) # unrecoverable crash
102
+
103
+
104
+ sys.excepthook = handle_all_unhandled_exceptions
105
+ # ------------------------------------------------------------------------------
106
+
107
+ # non-transpiled part, but shared names among langs
108
+
109
+ is_synchronous = argv.sync # 'async' not in os.path.basename(__file__)
110
+
111
+ rootDir = DIR_NAME + '/../../../'
112
+ rootDirForSkips = DIR_NAME + '/../../../'
113
+ envVars = os.environ
114
+ LOG_CHARS_LENGTH = 10000
115
+ ext = 'py'
116
+ proxyTestFileName = 'proxies'
117
+
118
+
119
+ def get_cli_arg_value(arg):
120
+ arg_exists = getattr(argv, arg) if hasattr(argv, arg) else False
121
+ with_hyphen = '--' + arg
122
+ arg_exists_with_hyphen = getattr(argv, with_hyphen) if hasattr(argv, with_hyphen) else False
123
+ without_hyphen = arg.replace('--', '')
124
+ arg_exists_wo_hyphen = getattr(argv, without_hyphen) if hasattr(argv, without_hyphen) else False
125
+ return arg_exists or arg_exists_with_hyphen or arg_exists_wo_hyphen
126
+
127
+ isWsTests = get_cli_arg_value('--ws')
128
+
129
+
130
+ class baseMainTestClass():
131
+ lang = 'PY'
132
+ is_synchronous = is_synchronous
133
+ request_tests_failed = False
134
+ response_tests_failed = False
135
+ response_tests = False
136
+ ws_tests = False
137
+ load_keys = False
138
+ skipped_settings_for_exchange = {}
139
+ skipped_methods = {}
140
+ check_public_tests = {}
141
+ test_files = {}
142
+ public_tests = {}
143
+ new_line = '\n'
144
+ root_dir = rootDir
145
+ env_vars = envVars
146
+ ext = ext
147
+ root_dir_for_skips = rootDirForSkips
148
+ only_specific_tests = []
149
+ proxy_test_file_name = proxyTestFileName
150
+ pass
151
+
152
+
153
+ def dump(*args):
154
+ print(' '.join([str(arg) for arg in args]))
155
+
156
+
157
+ def convert_ascii(str):
158
+ return str # stub
159
+
160
+ def json_parse(elem):
161
+ return json.loads(elem)
162
+
163
+
164
+ def json_stringify(elem):
165
+ return json.dumps(elem)
166
+
167
+
168
+ def convert_to_snake_case(content):
169
+ res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
170
+ return res.replace('o_h_l_c_v', 'ohlcv')
171
+
172
+
173
+ def get_test_name(methodName):
174
+ # stub
175
+ return methodName
176
+
177
+
178
+ def io_file_exists(path):
179
+ return os.path.isfile(path)
180
+
181
+
182
+ def io_file_read(path, decode=True):
183
+ fs = open(path, "r", encoding="utf-8")
184
+ content = fs.read()
185
+ if decode:
186
+ return json.loads(content)
187
+ else:
188
+ return content
189
+
190
+
191
+ def io_dir_read(path):
192
+ return os.listdir(path)
193
+
194
+
195
+ async def call_method(test_files, methodName, exchange, skippedProperties, args):
196
+ methodNameToCall = 'test_' + convert_to_snake_case(methodName)
197
+ return await getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
198
+
199
+
200
+ async def call_exchange_method_dynamically(exchange, methodName, args):
201
+ return await getattr(exchange, methodName)(*args)
202
+
203
+ def call_exchange_method_dynamically_sync(exchange, methodName, args):
204
+ return getattr(exchange, methodName)(*args)
205
+
206
+ async def call_overriden_method(exchange, methodName, args):
207
+ # needed for php
208
+ return await call_exchange_method_dynamically(exchange, methodName, args)
209
+
210
+ def exception_message(exc):
211
+ message = '[' + type(exc).__name__ + '] ' + "".join(format_exception(type(exc), exc, exc.__traceback__, limit=6))
212
+ if len(message) > LOG_CHARS_LENGTH:
213
+ # Accessing out of range element causes error
214
+ message = message[0:LOG_CHARS_LENGTH]
215
+ return message
216
+
217
+
218
+ def exit_script(code=0):
219
+ exit(code)
220
+
221
+
222
+ def get_exchange_prop(exchange, prop, defaultValue=None):
223
+ if hasattr(exchange, prop):
224
+ res = getattr(exchange, prop)
225
+ if res is not None and res != '':
226
+ return res
227
+ return defaultValue
228
+
229
+
230
+ def set_exchange_prop(exchange, prop, value):
231
+ setattr(exchange, prop, value)
232
+ # set snake case too
233
+ setattr(exchange, convert_to_snake_case(prop), value)
234
+
235
+
236
+ def init_exchange(exchangeId, args, is_ws=False):
237
+ if is_synchronous:
238
+ return getattr(ccxt_sync, exchangeId)(args)
239
+ if (is_ws):
240
+ return getattr(ccxtpro, exchangeId)(args)
241
+ return getattr(ccxt, exchangeId)(args)
242
+
243
+
244
+ async def get_test_files(properties, ws=False):
245
+ tests = {}
246
+ finalPropList = properties + [proxyTestFileName]
247
+ for i in range(0, len(finalPropList)):
248
+ methodName = finalPropList[i]
249
+ name_snake_case = convert_to_snake_case(methodName)
250
+ prefix = 'async' if not is_synchronous else 'sync'
251
+ dir_to_test = DIR_NAME + '/exchange/' + prefix + '/'
252
+ module_string = 'ccxt.test.exchange.' + prefix + '.test_' + name_snake_case
253
+ if (ws):
254
+ prefix = 'pro'
255
+ dir_to_test = DIR_NAME + '/../' + prefix + '/test/Exchange/'
256
+ module_string = 'ccxt.pro.test.Exchange.test_' + name_snake_case
257
+ filePathWithExt = dir_to_test + 'test_' + name_snake_case + '.py'
258
+ if (io_file_exists (filePathWithExt)):
259
+ imp = importlib.import_module(module_string)
260
+ tests[methodName] = imp # getattr(imp, finalName)
261
+ return tests
262
+
263
+ async def close(exchange):
264
+ if (not is_synchronous and hasattr(exchange, 'close')):
265
+ await exchange.close()
266
+
267
+ def is_null_value(value):
268
+ return value is None
269
+
270
+ def set_fetch_response(exchange: ccxt.Exchange, data):
271
+ if (is_synchronous):
272
+ def fetch(url, method='GET', headers=None, body=None):
273
+ return data
274
+ exchange.fetch = fetch
275
+ return exchange
276
+ async def fetch(url, method='GET', headers=None, body=None):
277
+ return data
278
+ exchange.fetch = fetch
279
+ return exchange
280
+
281
+
282
+ argvSymbol = argv.symbol if argv.symbol and '/' in argv.symbol else None
283
+ # in python, we check it through "symbol" arg (as opposed to JS/PHP) because argvs were already built above
284
+ argvMethod = argv.symbol if argv.symbol and '()' in argv.symbol else None
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from tests_helpers import get_cli_arg_value, is_synchronous, argv, argvSymbol, argvMethod
4
+
5
+ try:
6
+ import asyncio
7
+ except ImportError:
8
+ asyncio = None
9
+
10
+ from base.tests_init import base_tests_init # noqa: F401
11
+ from ccxt.pro.test.base.tests_init import test_base_init_ws # noqa: F401
12
+
13
+
14
+ # ########### args ###########
15
+ isWs = get_cli_arg_value('--ws')
16
+ isBaseTests = get_cli_arg_value('--baseTests')
17
+ run_all = get_cli_arg_value('--all')
18
+
19
+ # ###### base tests #######
20
+ if (isBaseTests):
21
+ if (isWs):
22
+ test_base_init_ws()
23
+ else:
24
+ base_tests_init()
25
+ print('base tests passed!')
26
+ if not run_all:
27
+ exit(0)
28
+
29
+ # ###### exchange tests #######
30
+ if (is_synchronous):
31
+ from tests_sync import testMainClass as testMainClassSync
32
+ testMainClassSync().init(argv.exchange, argvSymbol, argvMethod)
33
+ else:
34
+ from tests_async import testMainClass as testMainClassAsync
35
+ asyncio.run(testMainClassAsync().init(argv.exchange, argvSymbol, argvMethod))
@@ -1,268 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- import argparse
4
- import json
5
- # import logging
6
- import os
7
- import sys
8
- from traceback import format_tb, format_exception
9
-
10
- import importlib # noqa: E402
11
- import re
12
-
13
- # ------------------------------------------------------------------------------
14
- # logging.basicConfig(level=logging.INFO)
15
- # ------------------------------------------------------------------------------
16
- DIR_NAME = os.path.dirname(os.path.abspath(__file__))
17
- root = os.path.dirname(os.path.dirname(DIR_NAME))
18
- sys.path.append(root)
19
-
20
- import ccxt # noqa: E402
21
- import ccxt.pro as ccxtpro # noqa: E402
22
-
23
- # ------------------------------------------------------------------------------
24
- # from typing import Optional
25
- # from typing import List
26
- from ccxt.base.errors import NotSupported
27
- from ccxt.base.errors import ProxyError
28
- from ccxt.base.errors import OperationFailed
29
- # from ccxt.base.errors import ExchangeError
30
- from ccxt.base.errors import ExchangeNotAvailable
31
- from ccxt.base.errors import OnMaintenance
32
- from ccxt.base.errors import AuthenticationError
33
-
34
- # ------------------------------------------------------------------------------
35
-
36
- class Argv(object):
37
- id_tests = False
38
- static_tests = False
39
- ws_tests = False
40
- request_tests = False
41
- response_tests = False
42
-
43
- sandbox = False
44
- privateOnly = False
45
- private = False
46
- ws = False
47
- verbose = False
48
- nonce = None
49
- exchange = None
50
- symbol = None
51
- info = False
52
- pass
53
-
54
-
55
- argv = Argv()
56
- parser = argparse.ArgumentParser()
57
-
58
- parser.add_argument('--sandbox', action='store_true', help='enable sandbox mode')
59
- parser.add_argument('--privateOnly', action='store_true', help='run private tests only')
60
- parser.add_argument('--private', action='store_true', help='run private tests')
61
- parser.add_argument('--verbose', action='store_true', help='enable verbose output')
62
- parser.add_argument('--ws', action='store_true', help='websockets version')
63
- parser.add_argument('--info', action='store_true', help='enable info output')
64
- parser.add_argument('--static', action='store_true', help='run static tests')
65
- parser.add_argument('--useProxy', action='store_true', help='run static tests')
66
- parser.add_argument('--idTests', action='store_true', help='run brokerId tests')
67
- parser.add_argument('--responseTests', action='store_true', help='run response tests')
68
- parser.add_argument('--requestTests', action='store_true', help='run response tests')
69
- parser.add_argument('--nonce', type=int, help='integer')
70
- parser.add_argument('exchange', type=str, help='exchange id in lowercase', nargs='?')
71
- parser.add_argument('symbol', type=str, help='symbol in uppercase', nargs='?')
72
- parser.parse_args(namespace=argv)
73
-
74
- # ------------------------------------------------------------------------------
75
-
76
- path = os.path.dirname(ccxt.__file__)
77
- if 'site-packages' in os.path.dirname(ccxt.__file__):
78
- raise Exception("You are running test_async.py/test.py against a globally-installed version of the library! It was previously installed into your site-packages folder by pip or pip3. To ensure testing against the local folder uninstall it first with pip uninstall ccxt or pip3 uninstall ccxt")
79
-
80
- # ------------------------------------------------------------------------------
81
-
82
- Error = Exception
83
-
84
- # # print an error string
85
- # def dump_error(*args):
86
- # string = ' '.join([str(arg) for arg in args])
87
- # print(string)
88
- # sys.stderr.write(string + "\n")
89
- # sys.stderr.flush()
90
-
91
-
92
- def handle_all_unhandled_exceptions(type, value, traceback):
93
- dump((type), (value), '\n<UNHANDLED EXCEPTION>\n' + ('\n'.join(format_tb(traceback))))
94
- exit(1) # unrecoverable crash
95
-
96
-
97
- sys.excepthook = handle_all_unhandled_exceptions
98
- # ------------------------------------------------------------------------------
99
-
100
- # non-transpiled part, but shared names among langs
101
-
102
- is_synchronous = 'async' not in os.path.basename(__file__)
103
-
104
- rootDir = DIR_NAME + '/../../../'
105
- rootDirForSkips = DIR_NAME + '/../../../'
106
- envVars = os.environ
107
- LOG_CHARS_LENGTH = 10000
108
- ext = 'py'
109
- proxyTestFileName = 'proxies'
110
-
111
-
112
- def get_cli_arg_value(arg):
113
- arg_exists = getattr(argv, arg) if hasattr(argv, arg) else False
114
- with_hyphen = '--' + arg
115
- arg_exists_with_hyphen = getattr(argv, with_hyphen) if hasattr(argv, with_hyphen) else False
116
- without_hyphen = arg.replace('--', '')
117
- arg_exists_wo_hyphen = getattr(argv, without_hyphen) if hasattr(argv, without_hyphen) else False
118
- return arg_exists or arg_exists_with_hyphen or arg_exists_wo_hyphen
3
+ from tests_helpers import get_cli_arg_value, dump, exit_script, get_test_files, init_exchange, set_exchange_prop, call_method, exception_message, io_file_exists, io_file_read, baseMainTestClass, AuthenticationError, NotSupported, OperationFailed, OnMaintenance, ExchangeNotAvailable, ProxyError, get_exchange_prop, close, json_parse, json_stringify, is_null_value, io_dir_read, convert_ascii, call_exchange_method_dynamically, set_fetch_response, call_exchange_method_dynamically_sync # noqa: F401
119
4
 
120
- isWsTests = get_cli_arg_value('--ws')
121
-
122
-
123
- class baseMainTestClass():
124
- lang = 'PY'
125
- is_synchronous = is_synchronous
126
- request_tests_failed = False
127
- response_tests_failed = False
128
- response_tests = False
129
- ws_tests = False
130
- load_keys = False
131
- skipped_settings_for_exchange = {}
132
- skipped_methods = {}
133
- check_public_tests = {}
134
- test_files = {}
135
- public_tests = {}
136
- new_line = '\n'
137
- root_dir = rootDir
138
- env_vars = envVars
139
- ext = ext
140
- root_dir_for_skips = rootDirForSkips
141
- only_specific_tests = []
142
- proxy_test_file_name = proxyTestFileName
143
- pass
144
-
145
-
146
- def dump(*args):
147
- print(' '.join([str(arg) for arg in args]))
148
-
149
-
150
- def convert_ascii(str):
151
- return str # stub
152
-
153
- def json_parse(elem):
154
- return json.loads(elem)
155
-
156
-
157
- def json_stringify(elem):
158
- return json.dumps(elem)
159
-
160
-
161
- def convert_to_snake_case(content):
162
- res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
163
- return res.replace('o_h_l_c_v', 'ohlcv')
164
-
165
-
166
- def get_test_name(methodName):
167
- # stub
168
- return methodName
169
-
170
-
171
- def io_file_exists(path):
172
- return os.path.isfile(path)
173
-
174
-
175
- def io_file_read(path, decode=True):
176
- fs = open(path, "r", encoding="utf-8")
177
- content = fs.read()
178
- if decode:
179
- return json.loads(content)
180
- else:
181
- return content
182
-
183
-
184
- def io_dir_read(path):
185
- return os.listdir(path)
186
-
187
-
188
- def call_method(test_files, methodName, exchange, skippedProperties, args):
189
- methodNameToCall = 'test_' + convert_to_snake_case(methodName)
190
- return getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
191
-
192
-
193
- def call_exchange_method_dynamically(exchange, methodName, args):
194
- return getattr(exchange, methodName)(*args)
195
-
196
- def call_overriden_method(exchange, methodName, args):
197
- # needed for php
198
- return call_exchange_method_dynamically(exchange, methodName, args)
199
-
200
- def exception_message(exc):
201
- message = '[' + type(exc).__name__ + '] ' + "".join(format_exception(type(exc), exc, exc.__traceback__, limit=6))
202
- if len(message) > LOG_CHARS_LENGTH:
203
- # Accessing out of range element causes error
204
- message = message[0:LOG_CHARS_LENGTH]
205
- return message
206
-
207
-
208
- def exit_script(code=0):
209
- exit(code)
210
-
211
-
212
- def get_exchange_prop(exchange, prop, defaultValue=None):
213
- if hasattr(exchange, prop):
214
- res = getattr(exchange, prop)
215
- if res is not None and res != '':
216
- return res
217
- return defaultValue
218
-
219
-
220
- def set_exchange_prop(exchange, prop, value):
221
- setattr(exchange, prop, value)
222
- # set snake case too
223
- setattr(exchange, convert_to_snake_case(prop), value)
224
-
225
-
226
- def init_exchange(exchangeId, args, is_ws=False):
227
- if (is_ws):
228
- return getattr(ccxtpro, exchangeId)(args)
229
- return getattr(ccxt, exchangeId)(args)
230
-
231
-
232
- def get_test_files(properties, ws=False):
233
- tests = {}
234
- finalPropList = properties + [proxyTestFileName]
235
- for i in range(0, len(finalPropList)):
236
- methodName = finalPropList[i]
237
- name_snake_case = convert_to_snake_case(methodName)
238
- prefix = 'async' if not is_synchronous else 'sync'
239
- dir_to_test = DIR_NAME + '/' + prefix + '/'
240
- module_string = 'ccxt.test.' + prefix + '.test_' + name_snake_case
241
- if (ws):
242
- prefix = 'pro'
243
- dir_to_test = DIR_NAME + '/../' + prefix + '/test/Exchange/'
244
- module_string = 'ccxt.pro.test.Exchange.test_' + name_snake_case
245
- filePathWithExt = dir_to_test + 'test_' + name_snake_case + '.py'
246
- if (io_file_exists (filePathWithExt)):
247
- imp = importlib.import_module(module_string)
248
- tests[methodName] = imp # getattr(imp, finalName)
249
- return tests
250
-
251
- def close(exchange):
252
- if (not is_synchronous and hasattr(exchange, 'close')):
253
- exchange.close()
254
-
255
- def is_null_value(value):
256
- return value is None
257
-
258
- def set_fetch_response(exchange: ccxt.Exchange, data):
259
- def fetch(url, method='GET', headers=None, body=None):
260
- return data
261
- exchange.fetch = fetch
262
- return exchange
263
-
264
- # *********************************
265
- # ***** AUTO-TRANSPILER-START *****
266
5
  class testMainClass(baseMainTestClass):
267
6
  def parse_cli_args(self):
268
7
  self.response_tests = get_cli_arg_value('--responseTests')
@@ -451,7 +190,9 @@ class testMainClass(baseMainTestClass):
451
190
  args_stringified = '(' + exchange.json(args) + ')' # args.join() breaks when we provide a list of symbols or multidimensional array; "args.toString()" breaks bcz of "array to string conversion"
452
191
  dump(self.add_padding('[INFO] TESTING', 25), self.exchange_hint(exchange), method_name, args_stringified)
453
192
  call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
454
- # if it was passed successfully, add to the list of successfull tests
193
+ if self.info:
194
+ dump(self.add_padding('[INFO] TESTING DONE', 25), self.exchange_hint(exchange), method_name)
195
+ # add to the list of successed tests
455
196
  if is_public:
456
197
  self.checked_public_tests[method_name] = True
457
198
  return
@@ -506,7 +247,7 @@ class testMainClass(baseMainTestClass):
506
247
  # formatted message "[TEST_FAILURE] ..." and that output is then regex-matched by
507
248
  # run-tests.js, so the exceptions are still printed out to console from there.
508
249
  max_retries = 3
509
- args_stringified = exchange.json(args) # args.join() breaks when we provide a list of symbols | "args.toString()" breaks bcz of "array to string conversion"
250
+ args_stringified = exchange.json(args) # args.join() breaks when we provide a list of symbols or multidimensional array; "args.toString()" breaks bcz of "array to string conversion"
510
251
  for i in range(0, max_retries):
511
252
  try:
512
253
  self.test_method(method_name, exchange, args, is_public)
@@ -835,12 +576,16 @@ class testMainClass(baseMainTestClass):
835
576
  for j in range(0, max_retries):
836
577
  try:
837
578
  self.test_method(proxy_test_name, exchange, [], True)
838
- break # if successfull, then break
579
+ return # if successfull, then end the test
839
580
  except Exception as e:
840
581
  exception = e
582
+ exchange.sleep(j * 1000)
841
583
  # if exception was set, then throw it
842
- if exception:
584
+ if exception is not None:
843
585
  error_message = '[TEST_FAILURE] Failed ' + proxy_test_name + ' : ' + exception_message(exception)
586
+ # temporary comment the below, because c# transpilation failure
587
+ # throw new ExchangeError (errorMessage.toString ());
588
+ dump('[TEST_WARNING]' + str(error_message))
844
589
 
845
590
  def start_test(self, exchange, symbol):
846
591
  # we do not need to test aliases
@@ -1074,7 +819,10 @@ class testMainClass(baseMainTestClass):
1074
819
  output = None
1075
820
  request_url = None
1076
821
  try:
1077
- call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
822
+ if not self.is_synchronous:
823
+ call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
824
+ else:
825
+ call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
1078
826
  except Exception as e:
1079
827
  if not (isinstance(e, ProxyError)):
1080
828
  raise e
@@ -1092,8 +840,12 @@ class testMainClass(baseMainTestClass):
1092
840
  expected_result = exchange.safe_value(data, 'parsedResponse')
1093
841
  mocked_exchange = set_fetch_response(exchange, data['httpResponse'])
1094
842
  try:
1095
- unified_result = call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
1096
- self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
843
+ if not self.is_synchronous:
844
+ unified_result = call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
845
+ self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
846
+ else:
847
+ unified_result_sync = call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
848
+ self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
1097
849
  except Exception as e:
1098
850
  self.request_tests_failed = True
1099
851
  error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
@@ -1178,7 +930,8 @@ class testMainClass(baseMainTestClass):
1178
930
  # reset options
1179
931
  # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1180
932
  exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1181
- close(exchange)
933
+ if not self.is_synchronous:
934
+ close(exchange)
1182
935
  return True # in c# methods that will be used with promiseAll need to return something
1183
936
 
1184
937
  def test_exchange_response_statically(self, exchange_name, exchange_data, test_name=None):
@@ -1227,7 +980,8 @@ class testMainClass(baseMainTestClass):
1227
980
  # reset options
1228
981
  # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1229
982
  exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1230
- close(exchange)
983
+ if not self.is_synchronous:
984
+ close(exchange)
1231
985
  return True # in c# methods that will be used with promiseAll need to return something
1232
986
 
1233
987
  def get_number_of_tests_from_exchange(self, exchange, exchange_data, test_name=None):
@@ -1272,7 +1026,8 @@ class testMainClass(baseMainTestClass):
1272
1026
  if self.request_tests_failed or self.response_tests_failed:
1273
1027
  exit_script(1)
1274
1028
  else:
1275
- success_message = '[' + self.lang + '][TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
1029
+ prefix = '[SYNC]' if (self.is_synchronous) else ''
1030
+ success_message = '[' + self.lang + ']' + prefix + '[TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
1276
1031
  dump('[INFO]' + success_message)
1277
1032
 
1278
1033
  def run_static_response_tests(self, exchange_name=None, test=None):
@@ -1670,13 +1425,3 @@ class testMainClass(baseMainTestClass):
1670
1425
  assert broker_id == id, 'vertex - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1671
1426
  close(exchange)
1672
1427
  return True
1673
-
1674
- # ***** AUTO-TRANSPILER-END *****
1675
- # *******************************
1676
-
1677
-
1678
- if __name__ == '__main__':
1679
- argvSymbol = argv.symbol if argv.symbol and '/' in argv.symbol else None
1680
- # in python, we check it through "symbol" arg (as opposed to JS/PHP) because argvs were already built above
1681
- argvMethod = argv.symbol if argv.symbol and '()' in argv.symbol else None
1682
- (testMainClass().init(argv.exchange, argvSymbol, argvMethod))