286 lines
9.5 KiB
Python
286 lines
9.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import argparse
|
|
import json
|
|
# import logging
|
|
import os
|
|
import sys
|
|
from traceback import format_tb, format_exception
|
|
|
|
import importlib # noqa: E402
|
|
import re
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# logging.basicConfig(level=logging.INFO)
|
|
# ------------------------------------------------------------------------------
|
|
DIR_NAME = os.path.dirname(os.path.abspath(__file__))
|
|
root = os.path.dirname(os.path.dirname(DIR_NAME))
|
|
sys.path.append(root)
|
|
|
|
import ccxt.async_support as ccxt # noqa: E402
|
|
import ccxt as ccxt_sync # noqa: E402
|
|
import ccxt.pro as ccxtpro # noqa: E402
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# from typing import Optional
|
|
# from typing import List
|
|
from ccxt.base.errors import NotSupported # noqa: F401
|
|
from ccxt.base.errors import InvalidProxySettings # noqa: F401
|
|
from ccxt.base.errors import OperationFailed # noqa: F401
|
|
# from ccxt.base.errors import ExchangeError
|
|
from ccxt.base.errors import ExchangeNotAvailable # noqa: F401
|
|
from ccxt.base.errors import OnMaintenance # noqa: F401
|
|
from ccxt.base.errors import AuthenticationError # noqa: F401
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
class Argv(object):
|
|
id_tests = False
|
|
static_tests = False
|
|
ws_tests = False
|
|
request_tests = False
|
|
response_tests = False
|
|
sandbox = False
|
|
privateOnly = False
|
|
private = False
|
|
ws = False
|
|
verbose = False
|
|
nonce = None
|
|
exchange = None
|
|
symbol = None
|
|
info = False
|
|
sync = False
|
|
baseTests = False
|
|
exchangeTests = False
|
|
pass
|
|
|
|
|
|
argv = Argv()
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--sandbox', action='store_true', help='enable sandbox mode')
|
|
parser.add_argument('--privateOnly', action='store_true', help='run private tests only')
|
|
parser.add_argument('--private', action='store_true', help='run private tests')
|
|
parser.add_argument('--verbose', action='store_true', help='enable verbose output')
|
|
parser.add_argument('--ws', action='store_true', help='websockets version')
|
|
parser.add_argument('--info', action='store_true', help='enable info output')
|
|
parser.add_argument('--static', action='store_true', help='run static tests')
|
|
parser.add_argument('--useProxy', action='store_true', help='run static tests')
|
|
parser.add_argument('--idTests', action='store_true', help='run brokerId tests')
|
|
parser.add_argument('--responseTests', action='store_true', help='run response tests')
|
|
parser.add_argument('--response', action='store_true', help='run response tests')
|
|
parser.add_argument('--requestTests', action='store_true', help='run request tests')
|
|
parser.add_argument('--request', action='store_true', help='run request tests')
|
|
parser.add_argument('--sync', action='store_true', help='is sync')
|
|
parser.add_argument('--baseTests', action='store_true', help='is base tests')
|
|
parser.add_argument('--exchangeTests', action='store_true', help='is exchange tests')
|
|
parser.add_argument('exchange', type=str, help='exchange id in lowercase', nargs='?')
|
|
parser.add_argument('symbol', type=str, help='symbol in uppercase', nargs='?')
|
|
parser.parse_args(namespace=argv)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
path = os.path.dirname(ccxt.__file__)
|
|
if 'site-packages' in os.path.dirname(ccxt.__file__):
|
|
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")
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
Error = Exception
|
|
|
|
# # print an error string
|
|
# def dump_error(*args):
|
|
# string = ' '.join([str(arg) for arg in args])
|
|
# print(string)
|
|
# sys.stderr.write(string + "\n")
|
|
# sys.stderr.flush()
|
|
|
|
|
|
def handle_all_unhandled_exceptions(type, value, traceback):
|
|
dump('[TEST_FAILURE]', (type), (value), '\n<UNHANDLED EXCEPTION>\n' + ('\n'.join(format_tb(traceback))))
|
|
exit(1) # unrecoverable crash
|
|
|
|
|
|
sys.excepthook = handle_all_unhandled_exceptions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# non-transpiled part, but shared names among langs
|
|
|
|
EXT = 'py'
|
|
LANG = 'PY'
|
|
IS_SYNCHRONOUS = argv.sync # 'async' not in os.path.basename(__file__)
|
|
PROXY_TEST_FILE_NAME = 'proxies'
|
|
ROOT_DIR = DIR_NAME + '/../../../'
|
|
ENV_VARS = os.environ
|
|
NEW_LINE = '\n'
|
|
LOG_CHARS_LENGTH = 10000
|
|
|
|
|
|
|
|
def get_cli_arg_value(arg):
|
|
arg_exists = getattr(argv, arg) if hasattr(argv, arg) else False
|
|
with_hyphen = '--' + arg
|
|
arg_exists_with_hyphen = getattr(argv, with_hyphen) if hasattr(argv, with_hyphen) else False
|
|
without_hyphen = arg.replace('--', '')
|
|
arg_exists_wo_hyphen = getattr(argv, without_hyphen) if hasattr(argv, without_hyphen) else False
|
|
return arg_exists or arg_exists_with_hyphen or arg_exists_wo_hyphen
|
|
|
|
isWsTests = get_cli_arg_value('--ws')
|
|
|
|
def dump(*args):
|
|
print(' '.join([str(arg) for arg in args]))
|
|
|
|
|
|
def convert_ascii(str):
|
|
return str # stub
|
|
|
|
def json_parse(elem):
|
|
return json.loads(elem)
|
|
|
|
|
|
def json_stringify(elem):
|
|
return json.dumps(elem)
|
|
|
|
|
|
def convert_to_snake_case(content):
|
|
res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
|
|
return res.replace('o_h_l_c_v', 'ohlcv')
|
|
|
|
|
|
def get_test_name(methodName):
|
|
# stub
|
|
return methodName
|
|
|
|
|
|
def io_file_exists(path):
|
|
return os.path.isfile(path)
|
|
|
|
|
|
def io_file_read(path, decode=True):
|
|
fs = open(path, "r", encoding="utf-8")
|
|
content = fs.read()
|
|
if decode:
|
|
return json.loads(content)
|
|
else:
|
|
return content
|
|
|
|
|
|
def io_dir_read(path):
|
|
return os.listdir(path)
|
|
|
|
|
|
def call_method_sync(test_files, methodName, exchange, skippedProperties, args):
|
|
methodNameToCall = 'test_' + convert_to_snake_case(methodName)
|
|
return getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
|
|
|
|
async def call_method(test_files, methodName, exchange, skippedProperties, args):
|
|
methodNameToCall = 'test_' + convert_to_snake_case(methodName)
|
|
return await getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
|
|
|
|
|
|
async def call_exchange_method_dynamically(exchange, methodName, args):
|
|
return await getattr(exchange, methodName)(*args)
|
|
|
|
def call_exchange_method_dynamically_sync(exchange, methodName, args):
|
|
return getattr(exchange, methodName)(*args)
|
|
|
|
async def call_overriden_method(exchange, methodName, args):
|
|
# needed for php
|
|
return await call_exchange_method_dynamically(exchange, methodName, args)
|
|
|
|
def exception_message(exc):
|
|
message = '[' + type(exc).__name__ + '] ' + "".join(format_exception(type(exc), exc, exc.__traceback__, limit=6))
|
|
if len(message) > LOG_CHARS_LENGTH:
|
|
# Accessing out of range element causes error
|
|
message = message[0:LOG_CHARS_LENGTH]
|
|
return message
|
|
|
|
# stub for c#
|
|
def get_root_exception(exc):
|
|
return exc
|
|
|
|
def exit_script(code=0):
|
|
exit(code)
|
|
|
|
|
|
def get_exchange_prop(exchange, prop, defaultValue=None):
|
|
if hasattr(exchange, prop):
|
|
res = getattr(exchange, prop)
|
|
if res is not None and res != '':
|
|
return res
|
|
return defaultValue
|
|
|
|
|
|
def set_exchange_prop(exchange, prop, value):
|
|
setattr(exchange, prop, value)
|
|
# set snake case too
|
|
setattr(exchange, convert_to_snake_case(prop), value)
|
|
|
|
|
|
def init_exchange(exchangeId, args, is_ws=False):
|
|
if IS_SYNCHRONOUS:
|
|
return getattr(ccxt_sync, exchangeId)(args)
|
|
if (is_ws):
|
|
return getattr(ccxtpro, exchangeId)(args)
|
|
return getattr(ccxt, exchangeId)(args)
|
|
|
|
|
|
def get_test_files_sync(properties, ws=False):
|
|
tests = {}
|
|
finalPropList = properties + [PROXY_TEST_FILE_NAME, 'features']
|
|
for i in range(0, len(finalPropList)):
|
|
methodName = finalPropList[i]
|
|
name_snake_case = convert_to_snake_case(methodName)
|
|
prefix = 'async' if not IS_SYNCHRONOUS else 'sync'
|
|
dir_to_test = DIR_NAME + '/exchange/' + prefix + '/'
|
|
module_string = 'ccxt.test.exchange.' + prefix + '.test_' + name_snake_case
|
|
if (ws):
|
|
prefix = 'pro'
|
|
dir_to_test = DIR_NAME + '/../' + prefix + '/test/Exchange/'
|
|
module_string = 'ccxt.pro.test.Exchange.test_' + name_snake_case
|
|
filePathWithExt = dir_to_test + 'test_' + name_snake_case + '.py'
|
|
if (io_file_exists (filePathWithExt)):
|
|
imp = importlib.import_module(module_string)
|
|
tests[methodName] = imp # getattr(imp, finalName)
|
|
return tests
|
|
|
|
async def get_test_files(properties, ws=False):
|
|
return get_test_files_sync(properties, ws)
|
|
|
|
async def close(exchange):
|
|
if (not IS_SYNCHRONOUS and hasattr(exchange, 'close')):
|
|
await exchange.close()
|
|
|
|
def is_null_value(value):
|
|
return value is None
|
|
|
|
def set_fetch_response(exchange: ccxt.Exchange, data):
|
|
if (IS_SYNCHRONOUS):
|
|
def fetch(url, method='GET', headers=None, body=None):
|
|
return data
|
|
exchange.fetch = fetch
|
|
return exchange
|
|
async def fetch(url, method='GET', headers=None, body=None):
|
|
return data
|
|
exchange.fetch = fetch
|
|
return exchange
|
|
|
|
def get_lang():
|
|
return LANG
|
|
|
|
def get_ext():
|
|
return EXT
|
|
|
|
def get_root_dir():
|
|
return ROOT_DIR
|
|
|
|
def get_env_vars():
|
|
return ENV_VARS
|
|
|
|
def is_sync():
|
|
return IS_SYNCHRONOUS
|
|
|
|
argvExchange = argv.exchange
|
|
argvSymbol = argv.symbol if argv.symbol and '/' in argv.symbol else None
|
|
# in python, we check it through "symbol" arg (as opposed to JS/PHP) because argvs were already built above
|
|
argvMethod = argv.symbol if argv.symbol and '()' in argv.symbol else None
|