Coverage for torxtools/cfgtools.py: 60%

19 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-20 22:02 +0000

1""" 

2Functions for working with configuration file selection and reading. 

3 

4The :func:`which` convenience function returns the first file that should be used as configuration file from a list. 

5""" 

6 

7import os 

8import typing as t 

9 

10from boltons.iterutils import first, flatten_iter, unique_iter 

11from xdg import XDG_CONFIG_DIRS 

12 

13from . import xdgtools 

14 

15__all__ = [ 

16 "which", 

17 "candidates", 

18] 

19 

20 

21# pylint: disable=redefined-outer-name 

22def which( 

23 cfgfile: str = None, 

24 candidates: t.List[str] = None, 

25 default: str = "/dev/null", 

26 verify: t.Callable = os.path.exists, 

27) -> t.Optional[str]: 

28 """ 

29 Convenience function to return the configuration file to read. 

30 

31 Parameters 

32 ---------- 

33 cfgfile: str, None 

34 a single path. If not None, then it will be returned without calling the verify function. 

35 

36 candidates: t.List[str], None 

37 a list of paths. If cfgfile is None, then the verify function will be 

38 called for each of these paths and the first one for which verify 

39 returns True will be returned. 

40 

41 If no file is matched, then :file:`/dev/null` will be returned. 

42 

43 verify: t.Callable 

44 callable that will be called for every file in candidate. Defaults to os.path.exists. 

45 

46 default: str, None 

47 value to be returned if cfgfile is None and no match from candidates was found 

48 

49 Returns 

50 ------- 

51 str: 

52 cfgfile, a value from candidates, or default 

53 

54 Example 

55 ------- 

56 

57 .. code-block:: python 

58 

59 import argparse, sys 

60 from torxtools import cfgtools, pathtools 

61 

62 defaults = pathtools.expandpath(["~/.my-cfgfile"], ["/etc/cfgfile"]) 

63 

64 parser = argparse.ArgumentParser() 

65 parser.add_argument("--cfgfile") 

66 args = parser.parse_args(sys.argv[:1]) 

67 

68 print(cfgtools.which(args.cfgfile, defaults)) 

69 

70 """ 

71 if not callable(verify): 71 ↛ 72line 71 didn't jump to line 72 because the condition on line 71 was never true

72 raise TypeError(f"expected verify to be a callable, not: {verify}") 

73 

74 if cfgfile: 

75 return cfgfile 

76 return first(candidates or [], default=default, key=verify) 

77 

78 

79def candidates(cfgname: str = None) -> t.List[str]: 

80 """ 

81 Convenience function to return list of candidates paths for a configuration file. 

82 

83 Parameters 

84 ---------- 

85 cfgfile: str, None 

86 a single path. If not None, then it will be returned without calling the verify function. 

87 

88 Returns 

89 ------- 

90 list[str]: 

91 list of paths that are candidates 

92 

93 """ 

94 

95 # fmt: off 

96 # pylint: disable=invalid-name 

97 _CFGFILE_SEARCH_PATHS: t.List[str] = list( 

98 unique_iter( 

99 flatten_iter( 

100 [ 

101 "./.{cfgname}", # ./.flasket.yml 

102 "./{cfgname}", # ./flasket.yml 

103 "$XDG_CONFIG_HOME/{cfgname}", # ~/.config/flasket.yml 

104 "~/.{cfgname}", # ~/.flasket.yml 

105 [os.path.join(str(e), "{cfgname}") for e in XDG_CONFIG_DIRS], 

106 "/etc/{cfgname}", # /etc/flasket.yml 

107 ], 

108 ), 

109 ), 

110 ) 

111 # fmt: on 

112 # 

113 # Set the environment to ensure paths are calculated. 

114 xdgtools.setenv() 

115 

116 search_paths = _CFGFILE_SEARCH_PATHS 

117 if cfgname: 

118 search_paths = [e.format(cfgname=cfgname) for e in search_paths] 

119 return search_paths