Coverage for torxtools/argtools.py: 63%

51 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-18 01:02 +0000

1""" 

2Parser types for command-line options, arguments and sub-commands 

3 

4""" 

5 

6import os 

7import typing as t 

8from argparse import ArgumentTypeError 

9 

10__all__ = [ 

11 "is_int_positive", 

12 "is_int_positive_or_zero", 

13 "is_int_negative", 

14 "is_int_negative_or_zero", 

15 "is_file", 

16 "is_dir", 

17] 

18 

19 

20def _get_int_number(value: int, message: str) -> int: 

21 try: 

22 return int(value) 

23 except (ValueError, TypeError): 

24 raise ArgumentTypeError(message) from None 

25 

26 

27def is_int_positive(value: int) -> int: 

28 """ 

29 Verify that argument passed is a positive integer. 

30 

31 Parameters 

32 ---------- 

33 value: int 

34 value passed from argparser 

35 

36 Returns 

37 ------- 

38 int 

39 value passed from argparser 

40 

41 Example 

42 ------- 

43 

44 .. code-block:: 

45 

46 parser.add_argument( 

47 "--size", "-s", 

48 dest="size", 

49 help="[MB] Minimal size of attachment", 

50 type=torxtools.argtools.is_int_positive, 

51 default=100, 

52 ) 

53 """ 

54 message = f"value '{value}' must be positive" 

55 number = _get_int_number(value, message) 

56 if number <= 0: 

57 raise ArgumentTypeError(message) from None 

58 return number 

59 

60 

61def is_int_positive_or_zero(value: int) -> int: 

62 """ 

63 Verify that argument passed is a positive integer or zero. 

64 

65 Parameters 

66 ---------- 

67 value: int 

68 value passed from argparser 

69 

70 Returns 

71 ------- 

72 int 

73 value passed from argparser 

74 

75 Example 

76 ------- 

77 

78 .. code-block:: 

79 

80 parser.add_argument( 

81 "--size", "-s", 

82 dest="size", 

83 help="[MB] Minimal size of attachment", 

84 type=torxtools.argtools.is_int_positive_or_zero, 

85 default=100, 

86 ) 

87 """ 

88 message = f"value '{value}' must be positive or zero" 

89 number = _get_int_number(value, message) 

90 if number < 0: 

91 raise ArgumentTypeError(message) from None 

92 return number 

93 

94 

95def is_int_negative(value: int) -> int: 

96 """ 

97 Verify that argument passed is a negative integer. 

98 

99 Parameters 

100 ---------- 

101 value: int 

102 value passed from argparser 

103 

104 Returns 

105 ------- 

106 int 

107 value passed from argparser 

108 

109 Example 

110 ------- 

111 

112 .. code-block:: 

113 

114 parser.add_argument( 

115 "--temperature", "-t", 

116 dest="temperature", 

117 help="[C] Temperature colder than freezing point", 

118 type=torxtools.argtools.is_int_negative, 

119 default=-50, 

120 ) 

121 """ 

122 message = f"value '{value}' must be negative" 

123 number = _get_int_number(value, message) 

124 if number >= 0: 

125 raise ArgumentTypeError(message) from None 

126 return number 

127 

128 

129def is_int_negative_or_zero(value: int) -> int: 

130 """ 

131 Verify that argument passed is a negative integer or zero. 

132 

133 Parameters 

134 ---------- 

135 value: int 

136 value passed from argparser 

137 

138 Returns 

139 ------- 

140 int 

141 value passed from argparser 

142 

143 Example 

144 ------- 

145 

146 .. code-block:: 

147 

148 parser.add_argument( 

149 "--temperature", "-t", 

150 dest="temperature", 

151 help="[C] Temperature colder than freezing point", 

152 type=torxtools.argtools.is_int_negative_or_zero, 

153 default=-50, 

154 ) 

155 """ 

156 message = f"value '{value}' must be negative or zero" 

157 number = _get_int_number(value, message) 

158 if number > 0: 

159 raise ArgumentTypeError(message) from None 

160 return number 

161 

162 

163def is_file(value: str) -> t.Callable: 

164 """ 

165 Returns path if path is an existing regular file. 

166 This follows symbolic links 

167 

168 Parameters 

169 ---------- 

170 value: str 

171 value passed from argparser 

172 

173 Returns 

174 ------- 

175 str 

176 value passed from argparser 

177 

178 Example 

179 ------- 

180 

181 .. code-block:: 

182 

183 parser.add_argument( 

184 "-f", "--file" 

185 type=torxtools.argtools.is_file 

186 ) 

187 """ 

188 message = f"value '{value}' must be an existing file" 

189 if not os.path.isfile(str(value)): 

190 raise ArgumentTypeError(message) from None 

191 return value 

192 

193 

194def is_not_dir(value: str) -> t.Callable: 

195 """ 

196 Returns path if path is an existing file, including devices and not a directory. 

197 

198 Parameters 

199 ---------- 

200 value: str 

201 value passed from argparser 

202 

203 Returns 

204 ------- 

205 str 

206 value passed from argparser 

207 

208 Example 

209 ------- 

210 

211 .. code-block:: 

212 

213 parser.add_argument( 

214 "-f", "--file" 

215 type=torxtools.argtools.is_file 

216 ) 

217 """ 

218 message = f"value '{value}' must be an existing file" 

219 value = str(value) 

220 if not os.path.exists(str(value)): 

221 raise ArgumentTypeError(message) from None 

222 if os.path.isdir(str(value)): 

223 raise ArgumentTypeError(message) from None 

224 return value 

225 

226 

227def is_dir(value: str) -> t.Callable: 

228 """ 

229 Returns path if path is an existing regular directory. 

230 This follows symbolic links 

231 

232 Parameters 

233 ---------- 

234 value: str 

235 value passed from argparser 

236 

237 Returns 

238 ------- 

239 str 

240 value passed from argparser 

241 

242 Example 

243 ------- 

244 

245 .. code-block:: 

246 

247 parser.add_argument( 

248 "-f", "--dir" 

249 type=torxtools.argtools.is_dir 

250 ) 

251 """ 

252 message = f"value '{value}' must be an existing directory" 

253 if not os.path.isdir(str(value)): 

254 raise ArgumentTypeError(message) from None 

255 return value