simple_config: implement complex default values
Besides a literal value, the default can now also be a callable, which gets called with the config and evaluated as needed, lazily. This potentially allows e.g. the default value of one configvar to depend on the current value of another configvar.
This commit is contained in:
@@ -4,7 +4,7 @@ import time
|
||||
import os
|
||||
import stat
|
||||
from decimal import Decimal
|
||||
from typing import Union, Optional, Dict, Sequence, Tuple, Any, Set
|
||||
from typing import Union, Optional, Dict, Sequence, Tuple, Any, Set, Callable
|
||||
from numbers import Real
|
||||
from functools import cached_property
|
||||
|
||||
@@ -54,23 +54,34 @@ FINAL_CONFIG_VERSION = 3
|
||||
|
||||
class ConfigVar(property):
|
||||
|
||||
def __init__(self, key: str, *, default, type_=None):
|
||||
def __init__(
|
||||
self,
|
||||
key: str,
|
||||
*,
|
||||
default: Union[Any, Callable[['SimpleConfig'], Any]], # typically a literal, but can also be a callable
|
||||
type_=None,
|
||||
):
|
||||
self._key = key
|
||||
self._default = default
|
||||
self._type = type_
|
||||
property.__init__(self, self._get_config_value, self._set_config_value)
|
||||
|
||||
def _get_config_value(self, config: 'SimpleConfig'):
|
||||
value = config.get(self._key, default=self._default)
|
||||
if self._type is not None and value != self._default:
|
||||
assert value is not None, f"got None for key={self._key!r}"
|
||||
try:
|
||||
value = self._type(value)
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
f"ConfigVar.get type-check and auto-conversion failed. "
|
||||
f"key={self._key!r}. type={self._type}. value={value!r}") from e
|
||||
return value
|
||||
with config.lock:
|
||||
if config.is_set(self._key):
|
||||
value = config.get(self._key)
|
||||
if self._type is not None:
|
||||
assert value is not None, f"got None for key={self._key!r}"
|
||||
try:
|
||||
value = self._type(value)
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
f"ConfigVar.get type-check and auto-conversion failed. "
|
||||
f"key={self._key!r}. type={self._type}. value={value!r}") from e
|
||||
else:
|
||||
d = self._default
|
||||
value = d(config) if callable(d) else d
|
||||
return value
|
||||
|
||||
def _set_config_value(self, config: 'SimpleConfig', value, *, save=True):
|
||||
if self._type is not None and value is not None:
|
||||
@@ -817,14 +828,14 @@ class SimpleConfig(Logger):
|
||||
f"Either use config.cv.{name}.set() or assign to config.{name} instead.")
|
||||
return CVLookupHelper()
|
||||
|
||||
def get_swapserver_url(self):
|
||||
def _default_swapserver_url(self) -> str:
|
||||
if constants.net == constants.BitcoinMainnet:
|
||||
default = 'https://swaps.electrum.org/api'
|
||||
elif constants.net == constants.BitcoinTestnet:
|
||||
default = 'https://swaps.electrum.org/testnet'
|
||||
else:
|
||||
default = 'http://localhost:5455'
|
||||
return self.SWAPSERVER_URL or default
|
||||
return default
|
||||
|
||||
# config variables ----->
|
||||
NETWORK_AUTO_CONNECT = ConfigVar('auto_connect', default=True, type_=bool)
|
||||
@@ -940,7 +951,7 @@ class SimpleConfig(Logger):
|
||||
CONFIG_FORGET_CHANGES = ConfigVar('forget_config', default=False, type_=bool)
|
||||
|
||||
# submarine swap server
|
||||
SWAPSERVER_URL = ConfigVar('swapserver_url', default='', type_=str)
|
||||
SWAPSERVER_URL = ConfigVar('swapserver_url', default=_default_swapserver_url, type_=str)
|
||||
SWAPSERVER_PORT = ConfigVar('swapserver_port', default=5455, type_=int)
|
||||
TEST_SWAPSERVER_REFUND = ConfigVar('test_swapserver_refund', default=False, type_=bool)
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ class SwapManager(Logger):
|
||||
if swap.prepay_hash is not None:
|
||||
self.prepayments[swap.prepay_hash] = bytes.fromhex(k)
|
||||
# api url
|
||||
self.api_url = wallet.config.get_swapserver_url()
|
||||
self.api_url = wallet.config.SWAPSERVER_URL
|
||||
# init default min & max
|
||||
self.init_min_max_values()
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ import sys
|
||||
import os
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
from io import StringIO
|
||||
from electrum.simple_config import (SimpleConfig, read_user_config)
|
||||
|
||||
from electrum.simple_config import SimpleConfig, read_user_config
|
||||
from electrum import constants
|
||||
|
||||
from . import ElectrumTestCase
|
||||
|
||||
@@ -147,6 +148,22 @@ class Test_SimpleConfig(ElectrumTestCase):
|
||||
config.NETWORK_MAX_INCOMING_MSG_SIZE = None
|
||||
self.assertEqual(MAX_MSG_SIZE_DEFAULT, config.NETWORK_MAX_INCOMING_MSG_SIZE)
|
||||
|
||||
def test_configvars_get_default_value_complex_fn(self):
|
||||
config = SimpleConfig(self.options)
|
||||
self.assertEqual("https://swaps.electrum.org/api", config.SWAPSERVER_URL)
|
||||
|
||||
config.SWAPSERVER_URL = "http://localhost:9999"
|
||||
self.assertEqual("http://localhost:9999", config.SWAPSERVER_URL)
|
||||
|
||||
config.SWAPSERVER_URL = None
|
||||
self.assertEqual("https://swaps.electrum.org/api", config.SWAPSERVER_URL)
|
||||
|
||||
constants.set_testnet()
|
||||
try:
|
||||
self.assertEqual("https://swaps.electrum.org/testnet", config.SWAPSERVER_URL)
|
||||
finally:
|
||||
constants.set_mainnet()
|
||||
|
||||
def test_configvars_is_set(self):
|
||||
config = SimpleConfig(self.options)
|
||||
self.assertEqual(MAX_MSG_SIZE_DEFAULT, config.NETWORK_MAX_INCOMING_MSG_SIZE)
|
||||
|
||||
Reference in New Issue
Block a user