Coverage for sources/mimeogram/__/configuration.py: 100%
41 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-07 04:07 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-07 04:07 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Fundamental configuration. '''
24from . import imports as __
25from . import dictedits as _dictedits
26from . import distribution as _distribution
27from . import exceptions as _exceptions
28from . import io as _io
29from . import nomina as _nomina
32class EnablementTristate( __.enum.Enum ): # TODO: Python 3.11: StrEnum
33 ''' Disable, enable, or retain the natural state? '''
35 Disable = 'disable'
36 Retain = 'retain'
37 Enable = 'enable'
39 def __bool__( self ) -> bool:
40 if self.Disable is self: return False
41 if self.Enable is self: return True
42 raise _exceptions.OperationInvalidity( # noqa: TRY003
43 'inert enablement tristate', 'boolean translation' )
45 def is_retain( self ) -> bool:
46 ''' Does enum indicate a retain state? '''
47 return self.Retain is self
50async def acquire(
51 application_name: str,
52 directories: __.PlatformDirs,
53 distribution: _distribution.Information,
54 edits: _dictedits.Edits = ( ),
55 file: __.Absential[ __.Path ] = __.absent,
56) -> __.AccretiveDictionary[ str, __.typx.Any ]:
57 ''' Loads configuration as dictionary. '''
58 if __.is_absent( file ):
59 file = _discover_copy_template( directories, distribution )
60 configuration = await _acquire( file )
61 includes = await _acquire_includes(
62 application_name, directories, configuration.get( 'includes', ( ) ) )
63 for include in includes: configuration.update( include )
64 for edit in edits: edit( configuration )
65 return __.AccretiveDictionary( configuration )
68async def _acquire( file: __.Path ) -> _nomina.NominativeDictionary:
69 from aiofiles import open as open_ # pyright: ignore
70 from tomli import loads
71 async with open_( file ) as stream:
72 return loads( await stream.read( ) )
75async def _acquire_includes(
76 application_name: str,
77 directories: __.PlatformDirs,
78 specs: tuple[ str, ... ]
79) -> __.cabc.Sequence[ dict[ str, __.typx.Any ] ]:
80 from itertools import chain
81 from tomli import loads
82 locations = tuple(
83 __.Path( spec.format(
84 user_configuration = directories.user_config_path,
85 user_home = __.Path.home( ),
86 application_name = application_name ) )
87 for spec in specs )
88 iterables = tuple(
89 ( location.glob( '*.toml' ) if location.is_dir( ) else ( location, ) )
90 for location in locations )
91 return await _io.acquire_text_files_async(
92 *( file for file in chain.from_iterable( iterables ) ),
93 deserializer = loads )
96def _discover_copy_template(
97 directories: __.PlatformDirs, distribution: _distribution.Information
98) -> __.Path:
99 from shutil import copyfile
100 file = directories.user_config_path / 'general.toml'
101 if not file.exists( ):
102 copyfile(
103 distribution.provide_data_location(
104 'configuration', 'general.toml' ), file )
105 return file