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

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

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#============================================================================# 

19 

20 

21''' Fundamental configuration. ''' 

22 

23 

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 

30 

31 

32class EnablementTristate( __.enum.Enum ): # TODO: Python 3.11: StrEnum 

33 ''' Disable, enable, or retain the natural state? ''' 

34 

35 Disable = 'disable' 

36 Retain = 'retain' 

37 Enable = 'enable' 

38 

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

44 

45 def is_retain( self ) -> bool: 

46 ''' Does enum indicate a retain state? ''' 

47 return self.Retain is self 

48 

49 

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 ) 

66 

67 

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

73 

74 

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 ) 

94 

95 

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