Merge pull request #1746 from hroff-1902/json-defaults
Support for defaults in json schema
This commit is contained in:
@@ -9,7 +9,7 @@ from argparse import Namespace
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from jsonschema import Draft4Validator, validate
|
||||
from jsonschema import Draft4Validator, validators
|
||||
from jsonschema.exceptions import ValidationError, best_match
|
||||
|
||||
from freqtrade import OperationalException, constants
|
||||
@@ -34,6 +34,27 @@ def set_loggers(log_level: int = 0) -> None:
|
||||
logging.getLogger('telegram').setLevel(logging.INFO)
|
||||
|
||||
|
||||
def _extend_with_default(validator_class):
|
||||
validate_properties = validator_class.VALIDATORS["properties"]
|
||||
|
||||
def set_defaults(validator, properties, instance, schema):
|
||||
for prop, subschema in properties.items():
|
||||
if "default" in subschema:
|
||||
instance.setdefault(prop, subschema["default"])
|
||||
|
||||
for error in validate_properties(
|
||||
validator, properties, instance, schema,
|
||||
):
|
||||
yield error
|
||||
|
||||
return validators.extend(
|
||||
validator_class, {"properties": set_defaults},
|
||||
)
|
||||
|
||||
|
||||
ValidatorWithDefaults = _extend_with_default(Draft4Validator)
|
||||
|
||||
|
||||
class Configuration(object):
|
||||
"""
|
||||
Class to read and init the bot configuration
|
||||
@@ -331,7 +352,7 @@ class Configuration(object):
|
||||
:return: Returns the config if valid, otherwise throw an exception
|
||||
"""
|
||||
try:
|
||||
validate(conf, constants.CONF_SCHEMA, Draft4Validator)
|
||||
ValidatorWithDefaults(constants.CONF_SCHEMA).validate(conf)
|
||||
return conf
|
||||
except ValidationError as exception:
|
||||
logger.critical(
|
||||
|
@@ -173,10 +173,10 @@ CONF_SCHEMA = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'name': {'type': 'string'},
|
||||
'sandbox': {'type': 'boolean'},
|
||||
'key': {'type': 'string'},
|
||||
'secret': {'type': 'string'},
|
||||
'password': {'type': 'string'},
|
||||
'sandbox': {'type': 'boolean', 'default': False},
|
||||
'key': {'type': 'string', 'default': ''},
|
||||
'secret': {'type': 'string', 'default': ''},
|
||||
'password': {'type': 'string', 'default': ''},
|
||||
'uid': {'type': 'string'},
|
||||
'pair_whitelist': {
|
||||
'type': 'array',
|
||||
@@ -199,7 +199,7 @@ CONF_SCHEMA = {
|
||||
'ccxt_config': {'type': 'object'},
|
||||
'ccxt_async_config': {'type': 'object'}
|
||||
},
|
||||
'required': ['name', 'key', 'secret', 'pair_whitelist']
|
||||
'required': ['name', 'pair_whitelist']
|
||||
},
|
||||
'edge': {
|
||||
'type': 'object',
|
||||
|
@@ -53,7 +53,7 @@ class FreqtradeBot(object):
|
||||
|
||||
self.rpc: RPCManager = RPCManager(self)
|
||||
|
||||
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
||||
exchange_name = self.config.get('exchange', {}).get('name').title()
|
||||
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
||||
|
||||
self.wallets = Wallets(self.config, self.exchange)
|
||||
|
@@ -68,7 +68,7 @@ class Backtesting(object):
|
||||
self.config['dry_run'] = True
|
||||
self.strategylist: List[IStrategy] = []
|
||||
|
||||
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
||||
exchange_name = self.config.get('exchange', {}).get('name').title()
|
||||
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
||||
self.fee = self.exchange.get_fee()
|
||||
|
||||
|
@@ -18,6 +18,15 @@ from freqtrade.state import RunMode
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def all_conf():
|
||||
config_file = Path(__file__).parents[2] / "config_full.json.example"
|
||||
print(config_file)
|
||||
configuration = Configuration(Namespace())
|
||||
conf = configuration._load_config_file(str(config_file))
|
||||
return conf
|
||||
|
||||
|
||||
def test_load_config_invalid_pair(default_conf) -> None:
|
||||
default_conf['exchange']['pair_whitelist'].append('ETH-BTC')
|
||||
|
||||
@@ -608,3 +617,59 @@ def test_validate_tsl(default_conf):
|
||||
default_conf['trailing_stop_positive_offset'] = 0.015
|
||||
Configuration(Namespace())
|
||||
configuration._validate_config_consistency(default_conf)
|
||||
|
||||
|
||||
def test_load_config_default_exchange(all_conf) -> None:
|
||||
"""
|
||||
config['exchange'] subtree has required options in it
|
||||
so it cannot be omitted in the config
|
||||
"""
|
||||
del all_conf['exchange']
|
||||
|
||||
assert 'exchange' not in all_conf
|
||||
|
||||
with pytest.raises(ValidationError,
|
||||
match=r'\'exchange\' is a required property'):
|
||||
configuration = Configuration(Namespace())
|
||||
configuration._validate_config_schema(all_conf)
|
||||
|
||||
|
||||
def test_load_config_default_exchange_name(all_conf) -> None:
|
||||
"""
|
||||
config['exchange']['name'] option is required
|
||||
so it cannot be omitted in the config
|
||||
"""
|
||||
del all_conf['exchange']['name']
|
||||
|
||||
assert 'name' not in all_conf['exchange']
|
||||
|
||||
with pytest.raises(ValidationError,
|
||||
match=r'\'name\' is a required property'):
|
||||
configuration = Configuration(Namespace())
|
||||
configuration._validate_config_schema(all_conf)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("keys", [("exchange", "sandbox", False),
|
||||
("exchange", "key", ""),
|
||||
("exchange", "secret", ""),
|
||||
("exchange", "password", ""),
|
||||
])
|
||||
def test_load_config_default_subkeys(all_conf, keys) -> None:
|
||||
"""
|
||||
Test for parameters with default values in sub-paths
|
||||
so they can be omitted in the config and the default value
|
||||
should is added to the config.
|
||||
"""
|
||||
# Get first level key
|
||||
key = keys[0]
|
||||
# get second level key
|
||||
subkey = keys[1]
|
||||
|
||||
del all_conf[key][subkey]
|
||||
|
||||
assert subkey not in all_conf[key]
|
||||
|
||||
configuration = Configuration(Namespace())
|
||||
configuration._validate_config_schema(all_conf)
|
||||
assert subkey in all_conf[key]
|
||||
assert all_conf[key][subkey] == keys[2]
|
||||
|
Reference in New Issue
Block a user