diff --git a/ruyi/config/errors.py b/ruyi/config/errors.py index 1e42109..dc8524c 100644 --- a/ruyi/config/errors.py +++ b/ruyi/config/errors.py @@ -48,7 +48,7 @@ def __repr__(self) -> str: class InvalidConfigValueError(ValueError): def __init__( self, - key: str | Sequence[str], + key: str | Sequence[str] | type, val: object | None, ) -> None: super().__init__() @@ -56,7 +56,9 @@ def __init__( self._val = val def __str__(self) -> str: - return f"invalid value for config key {self._key}: {self._val}" + if isinstance(self._key, type): + return f"invalid config value for type {self._key}: {self._val}" + return f"invalid config value for key {self._key}: {self._val}" def __repr__(self) -> str: return f"InvalidConfigValueError({self._key:!r}, {self._val:!r})" diff --git a/ruyi/config/schema.py b/ruyi/config/schema.py index 7456c80..a034c3c 100644 --- a/ruyi/config/schema.py +++ b/ruyi/config/schema.py @@ -159,13 +159,17 @@ def encode_value(v: object) -> str: def decode_value( - key: str | Sequence[str], + key: str | Sequence[str] | type, val: str, ) -> object: """Decodes the given string representation of a config value into a Python value, directed by type information implied by the config key.""" - expected_type = get_expected_type_for_config_key(key) + if isinstance(key, type): + expected_type = key + else: + expected_type = get_expected_type_for_config_key(key) + if expected_type is bool: if val in ("true", "yes", "1"): return True diff --git a/tests/config/test_schema.py b/tests/config/test_schema.py index f40e358..35c2010 100644 --- a/tests/config/test_schema.py +++ b/tests/config/test_schema.py @@ -8,21 +8,24 @@ def test_decode_value_bool() -> None: assert decode_value("installation.externally_managed", "true") is True - assert decode_value("installation.externally_managed", "false") is False - assert decode_value("installation.externally_managed", "yes") is True - assert decode_value("installation.externally_managed", "no") is False - assert decode_value("installation.externally_managed", "1") is True - assert decode_value("installation.externally_managed", "0") is False + + assert decode_value(bool, "true") is True + assert decode_value(bool, "false") is False + assert decode_value(bool, "yes") is True + assert decode_value(bool, "no") is False + assert decode_value(bool, "1") is True + assert decode_value(bool, "0") is False with pytest.raises(InvalidConfigValueError): - decode_value("installation.externally_managed", "invalid") + decode_value(bool, "invalid") with pytest.raises(InvalidConfigValueError): - decode_value("installation.externally_managed", "x") + decode_value(bool, "x") with pytest.raises(InvalidConfigValueError): - decode_value("installation.externally_managed", "True") + decode_value(bool, "True") def test_decode_value_str() -> None: assert decode_value("repo.branch", "main") == "main" + assert decode_value(str, "main") == "main" def test_decode_value_datetime() -> None: @@ -30,9 +33,10 @@ def test_decode_value_datetime() -> None: assert ( decode_value("telemetry.upload_consent", "2024-12-01T12:00:00Z") == tz_aware_dt ) + assert decode_value(datetime.datetime, "2024-12-01T12:00:00Z") == tz_aware_dt # naive datetimes are decoded using the implicit local timezone - decode_value("telemetry.upload_consent", "2024-12-01T12:00:00") + decode_value(datetime.datetime, "2024-12-01T12:00:00") def test_encode_value_bool() -> None: