Coverage for /home/runner/work/coxbuild/coxbuild/src/coxbuild/configuration.py: 0%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

59 statements  

1import os 

2from pathlib import Path 

3from typing import Any 

4 

5 

6class Configuration: 

7 """Build configuration, entry key is case-insensitive.""" 

8 

9 def __init__(self, name: str = "", data: dict[str, Any] | None = None) -> None: 

10 """ 

11 Create configuration. 

12 

13 name: section name 

14 data: data source 

15 """ 

16 self.name = name 

17 self.data: dict[str, Any] = data if data is not None else {} 

18 self.cache: dict[str, Configuration] = {} 

19 if not self.name: 

20 self.loadenv() 

21 

22 def copy(self) -> "Configuration": 

23 """Copy configuration.""" 

24 return Configuration(self.name, self.data.copy()) 

25 

26 def _getid(self, attr: str) -> str: 

27 return (self.name + ":" + attr if self.name else attr).lower() 

28 

29 def __iter__(self): 

30 pre = "" 

31 if self.name: 

32 pre = f"{self.name}:" 

33 return (key for key in self.data if key.startswith(pre)) 

34 

35 def get(self, key: str) -> Any | None: 

36 id = self._getid(key) 

37 return self.data.get(id) 

38 

39 def __getitem__(self, key: str) -> Any: 

40 id = self._getid(key) 

41 return self.data[id] 

42 

43 def __setitem__(self, key: str, value: Any) -> None: 

44 id = self._getid(key) 

45 self.data[id] = value 

46 

47 def __delitem__(self, key: str) -> None: 

48 id = self._getid(key) 

49 del self.data[id] 

50 

51 def section(self, name: str): 

52 """ 

53 Get sub-section. 

54 

55 name: sub-section name 

56 """ 

57 if name not in self.cache: 

58 self.cache[name] = Configuration(self._getid(name), self.data) 

59 return self.cache[name] 

60 

61 def env(self): 

62 """Get environ section.""" 

63 return self.section("env") 

64 

65 def envbuild(self): 

66 """Get environ:coxbuild section.""" 

67 return self.env().section("coxbuild") 

68 

69 def loadenv(self): 

70 """Load environ section from os.""" 

71 env = self.env() 

72 for key in os.environ: 

73 env[key] = os.getenv(key) 

74 

75 

76class ConfigurationAccessor: 

77 """Configuration accessor.""" 

78 

79 __configname__ = "" 

80 

81 def __init__(self, config: Configuration) -> None: 

82 self.rootConfig = config 

83 if self.__configname__: 

84 self.config = config.section(self.__configname__) 

85 self.fallback = config.envbuild().section(self.__configname__) 

86 else: 

87 self.config = config 

88 self.fallback = config.envbuild() 

89 

90 def get(self, key: str) -> Any: 

91 """Get configuration value (or fallback).""" 

92 return self.config.get(key) or self.fallback.get(key) 

93 

94 def getPath(self, key: str) -> Path | None: 

95 """Get configuration value (or fallback) as Path.""" 

96 value: Path | None | str = self.get(key) 

97 if isinstance(value, str): 

98 value = Path(value) 

99 return value