Coverage for mymeco/config.py: 97%
50 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-01-15 20:56 +0000
« 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
9from mymeco import exceptions as exc
12@dataclasses.dataclass
13class LogConfig:
14 """Log configuration dataclass."""
16 verbosity_count: int
17 quiet_count: int
18 colored: bool
21class Configuration():
22 """Handle configuration file."""
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 ]
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 }
55 def __init__(self,
56 configfile: typing.Optional[str] = None) -> None:
57 """
58 Read configuration file and store config keys.
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
76 if configfile is None:
77 self.__log.warning('No configuration file found')
78 raise exc.NoConfigurationFile()
80 self.__configfile = configfile
81 self.__config = configparser.ConfigParser()
82 self.__config.read(self.__configfile)
84 @property
85 def configfile(self) -> str:
86 """
87 Get configuration file found.
89 :return: Full path of found configuration file where data are
90 extracted.
91 """
92 return self.__configfile
94 def log(
95 self
96 ) -> LogConfig:
97 """
98 Get logger configuration.
100 Read configuration file and extract right configuration for logger,
101 ready to be passed to ``mymeco.logger.configure`` function.
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 )
122 def tmdb(
123 self
124 ) -> typing.Mapping[str, str]:
125 """
126 Get TMDb configuration.
128 Read configuration file and extract The Movie Database configuration.
130 :return: Configuration map to access TMDb service. Output contains at
131 least the following keys:
132 * `token`: access token
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)
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)
146 return {
147 'token': token
148 }
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