mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-24 12:32:45 +08:00
feat(config): add explicit validation for required configuration fields (#2078)
* feat(config): add explicit validation for required configuration fields * feat(config): add explicit validation for required configuration fields * fix(config): always validate configuration regardless of registration * config: clarify validation semantics and document future migration plan * fix: pylint error --------- Co-authored-by: Linlang <Lv.Linlang@hotmail.com>
This commit is contained in:
@@ -63,16 +63,33 @@ QSETTINGS = QSettings()
|
||||
|
||||
class Config:
|
||||
def __init__(self, default_conf):
|
||||
self.__dict__["_default_config"] = copy.deepcopy(default_conf) # avoiding conflicts with __getattr__
|
||||
self.__dict__["_default_config"] = copy.deepcopy(default_conf)
|
||||
self.reset()
|
||||
|
||||
# TODO: This validation logic is a temporary solution.
|
||||
# The long-term goal is to migrate Qlib Config to a typed configuration
|
||||
# system based on pydantic.BaseModel, with explicit schema and field validation.
|
||||
def validate(self):
|
||||
errors = []
|
||||
|
||||
if not self.get("provider_uri"):
|
||||
errors.append("provider_uri must be set (e.g. ~/.qlib/qlib_data or a valid path)")
|
||||
|
||||
if not self.get("region"):
|
||||
errors.append("region must be specified (e.g. 'cn', 'us')")
|
||||
|
||||
if errors:
|
||||
raise ValueError(
|
||||
"Invalid Qlib configuration (note: the global config has already been updated):\n"
|
||||
"Invalid Qlib configuration:\n- " + "\n- ".join(errors)
|
||||
)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.__dict__["_config"][key]
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr in self.__dict__["_config"]:
|
||||
return self.__dict__["_config"][attr]
|
||||
|
||||
raise AttributeError(f"No such `{attr}` in self._config")
|
||||
|
||||
def get(self, key, default=None):
|
||||
@@ -116,8 +133,11 @@ class Config:
|
||||
return
|
||||
|
||||
C.set_conf_from_C(config)
|
||||
C.validate()
|
||||
|
||||
if C.logging_config:
|
||||
set_log_with_config(C.logging_config)
|
||||
|
||||
C.register()
|
||||
|
||||
|
||||
|
||||
17
qlib/tests/test_config_validation.py
Normal file
17
qlib/tests/test_config_validation.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from qlib.config import Config
|
||||
|
||||
|
||||
def test_missing_provider_uri_raises():
|
||||
default_conf = {
|
||||
"provider_uri": None,
|
||||
"region": "us",
|
||||
}
|
||||
|
||||
cfg = Config(default_conf)
|
||||
|
||||
with pytest.raises(ValueError) as exc:
|
||||
cfg.validate()
|
||||
|
||||
assert "provider_uri must be set" in str(exc.value)
|
||||
Reference in New Issue
Block a user