Coverage for mymeco/config.py: 97%

50 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-01-15 20:56 +0000

1# coding: utf-8 

2"""Handle application configuration file.""" 

3import os 

4import logging 

5import typing 

6import configparser 

7import dataclasses 

8 

9from mymeco import exceptions as exc 

10 

11 

12@dataclasses.dataclass 

13class LogConfig: 

14 """Log configuration dataclass.""" 

15 

16 verbosity_count: int 

17 quiet_count: int 

18 colored: bool 

19 

20 

21class Configuration(): 

22 """Handle configuration file.""" 

23 

24 __log: logging.Logger = logging.getLogger() 

25 __filelist: typing.Iterable[str] = [ 

26 os.path.join(os.environ.get('HOME', '/root'), '.mymeco'), 

27 os.path.join( 

28 os.environ.get( 

29 'XDG_CONFIG_HOME', 

30 os.path.join(os.environ.get('HOME', '/root'), '.config') 

31 ), 

32 'mymeco', 

33 'config' 

34 ), 

35 os.path.join( 

36 os.environ.get( 

37 'XDG_CONFIG_DIRS', 

38 os.path.join(os.sep, 'etc', 'xdg') 

39 ), 

40 'mymeco', 

41 'config' 

42 ) 

43 ] 

44 

45 __level_map: typing.Mapping[str, typing.Tuple[int, int]] = { 

46 'critical': (0, 3), 

47 'critic': (0, 3), 

48 'error': (0, 2), 

49 'warn': (0, 1), 

50 'warning': (0, 1), 

51 'info': (0, 0), 

52 'debug': (1, 0) 

53 } 

54 

55 def __init__(self, 

56 configfile: typing.Optional[str] = None) -> None: 

57 """ 

58 Read configuration file and store config keys. 

59 

60 :param configfile: Set configuration file to use a specific one. If 

61 not defined, will try to autodetect a configuration file at the 

62 following location: 

63 - ``$HOME/.mymeco`` 

64 - ``$XDG_CONFIG_HOME/mymeco/config`` 

65 (or ``~/.config/mymeco/config``) 

66 - ``$XDG_CONFIG_DIRS/mymeco/config`` 

67 (or ``/etc/xdg/mymeco/config``) 

68 - ``$HOME/.config/mymeco/config`` 

69 """ 

70 if configfile is None: 

71 # Detect config file 

72 configfile = self.__autodetect() 

73 elif not os.path.isfile(configfile): 

74 configfile = None 

75 

76 if configfile is None: 

77 self.__log.warning('No configuration file found') 

78 raise exc.NoConfigurationFile() 

79 

80 self.__configfile = configfile 

81 self.__config = configparser.ConfigParser() 

82 self.__config.read(self.__configfile) 

83 

84 @property 

85 def configfile(self) -> str: 

86 """ 

87 Get configuration file found. 

88 

89 :return: Full path of found configuration file where data are 

90 extracted. 

91 """ 

92 return self.__configfile 

93 

94 def log( 

95 self 

96 ) -> LogConfig: 

97 """ 

98 Get logger configuration. 

99 

100 Read configuration file and extract right configuration for logger, 

101 ready to be passed to ``mymeco.logger.configure`` function. 

102 

103 :return: Ready to use `kwargs` for ``mymeco.logger.configure`` method. 

104 """ 

105 if self.__config.has_section('log'): 

106 level = str(self.__config['log'].get('level')).lower() 

107 try: 

108 colored = self.__config['log'].getboolean('colored') 

109 if colored is None: 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true

110 colored = False 

111 except ValueError: 

112 colored = True 

113 (verb, quiet) = self.__level_map.get(level, (0, 0)) 

114 else: 

115 verb, quiet, colored = (0, 0, True) 

116 return LogConfig( 

117 verbosity_count=verb, 

118 quiet_count=quiet, 

119 colored=colored 

120 ) 

121 

122 def tmdb( 

123 self 

124 ) -> typing.Mapping[str, str]: 

125 """ 

126 Get TMDb configuration. 

127 

128 Read configuration file and extract The Movie Database configuration. 

129 

130 :return: Configuration map to access TMDb service. Output contains at 

131 least the following keys: 

132 * `token`: access token 

133 

134 :raises: ``MissingConfiguration`` exception is raised when 

135 configuration entry is missing. 

136 """ 

137 if not self.__config.has_section('tmdb'): 

138 raise exc.MissingConfiguration('tmdb', None, self.configfile) 

139 

140 token: typing.Union[None, str] = self.__config['tmdb'].get( 

141 'token', None 

142 ) 

143 if token is None: 

144 raise exc.MissingConfiguration('tmdb', 'token', self.configfile) 

145 

146 return { 

147 'token': token 

148 } 

149 

150 def __autodetect(self) -> typing.Union[str, None]: 

151 for config in self.__filelist: 

152 if os.path.isfile(config): 

153 return config 

154 return None