Coverage for functions \ flipdare \ core \ config_option.py: 69%
36 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
1# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
2#
3# This file is part of Flipdare's proprietary software and contains
4# confidential and copyrighted material. Unauthorised copying,
5# modification, distribution, or use of this file is strictly
6# prohibited without prior written permission from Flipdare Pty Ltd.
7#
8# This software includes third-party components licensed under MIT,
9# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
10#
12import os
13from typing import Any
14from flipdare.app_log import LOG
15from flipdare.config_key import ConfigKey, ConfigType
17__all__ = ["ConfigOption"]
19_TRUE = {"true", "1", "yes", "on", "t"}
20_FALSE = {"false", "0", "no", "off", "f"}
23class ConfigOption:
24 def __init__(self, key: ConfigKey, default_override: ConfigType | None = None) -> None:
25 self._key = key
26 default = default_override if default_override is not None else key._default_value
27 raw_env = os.environ.get(key.value)
29 if raw_env is None:
30 self._value = default
31 else:
32 self._value = self._parse(key, raw_env, default)
34 if self._value is None:
35 raise ValueError(f"Config key {key.value} is missing and has no default.")
37 def _parse(self, key: ConfigKey, val: str, default: Any) -> Any:
39 if key._value_type is bool:
40 s = str(val).lower()
41 if s in _TRUE:
42 return True
43 if s in _FALSE:
44 return False
45 raise ValueError("Not a boolean")
47 try:
48 # For int, float, str, just call the type constructor
49 return key._value_type(val)
50 except (ValueError, TypeError):
51 LOG().warning(
52 f"Invalid {key._value_type.__name__} for {key.value}: {val}. Using: {default}",
53 )
54 return default
56 @property
57 def key(self) -> ConfigKey:
58 return self._key
60 @property
61 def value(self) -> ConfigType | None:
62 return self._value
65# def as_any(self) -> Any:
66# # try to infer, bool, int, str
67# value = self._value
68#
69# # try bool
70# lower_value = value.lower()
71# if lower_value in _true:
72# return True
73# if lower_value in _false:
74# return False
75#
76# # try int
77# try:
78# return int(value)
79# except ValueError:
80# pass
81#
82# # try float
83# try:
84# return float(value)
85# except ValueError:
86# pass
87#
88# # default to str
89# return value
90#
91# def as_bool(self, default_value: bool | None = False) -> bool:
92# """Get a boolean environment variable."""
93# value = os.environ.get(self.key, str(default_value)).lower()
94# return value in _true
95#
96# def as_int(self) -> int:
97#
98# if self.key not in os.environ:
99# return default_value
100#
101# try:
102# return int(os.environ[self.key])
103# except ValueError:
104# return default_value
105#
106# def as_str(self, def_value: str | None = None) -> str | None:
107# if self.key in os.environ:
108# return os.environ[self.key]
109# return def_value