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

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# 

11 

12import os 

13from typing import Any 

14from flipdare.app_log import LOG 

15from flipdare.config_key import ConfigKey, ConfigType 

16 

17__all__ = ["ConfigOption"] 

18 

19_TRUE = {"true", "1", "yes", "on", "t"} 

20_FALSE = {"false", "0", "no", "off", "f"} 

21 

22 

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) 

28 

29 if raw_env is None: 

30 self._value = default 

31 else: 

32 self._value = self._parse(key, raw_env, default) 

33 

34 if self._value is None: 

35 raise ValueError(f"Config key {key.value} is missing and has no default.") 

36 

37 def _parse(self, key: ConfigKey, val: str, default: Any) -> Any: 

38 

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") 

46 

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 

55 

56 @property 

57 def key(self) -> ConfigKey: 

58 return self._key 

59 

60 @property 

61 def value(self) -> ConfigType | None: 

62 return self._value 

63 

64 

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