Coverage for yuio / ty.py: 100%

57 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-29 19:55 +0000

1# Yuio project, MIT license. 

2# 

3# https://github.com/taminomara/yuio/ 

4# 

5# You're free to copy this file to your project and edit it for your needs, 

6# just keep this copyright line please :3 

7 

8""" 

9Type annotations are unfortunately bulky. Yuio provides shortcuts for common annotated 

10types such as positive ints or non-empty containers. 

11 

12.. type:: PosInt 

13 :canonical: typing.Annotated[int, ~yuio.parse.Gt(0)] 

14 

15 Positive int. 

16 

17.. type:: NonNegInt 

18 :canonical: typing.Annotated[int, ~yuio.parse.Ge(0)] 

19 

20 Non-negative int. 

21 

22.. type:: PosFloat 

23 :canonical: typing.Annotated[float, ~yuio.parse.Gt(0)] 

24 

25 Positive float. 

26 

27.. type:: NonNegFloat 

28 :canonical: typing.Annotated[float, ~yuio.parse.Ge(0)] 

29 

30 Non-negative float. 

31 

32.. type:: NonEmptyStr 

33 :canonical: typing.Annotated[str, ~yuio.parse.LenGt(0)] 

34 

35 Non-empty string. 

36 

37.. type:: NonEmptyList 

38 :canonical: typing.Annotated[list[T], ~yuio.parse.LenGt(0)] 

39 

40 Non-empty list. 

41 

42.. type:: NonEmptySet 

43 :canonical: typing.Annotated[set[T], ~yuio.parse.LenGt(0)] 

44 

45 Non-empty set. 

46 

47.. type:: NonEmptyFrozenSet 

48 :canonical: typing.Annotated[frozenset[T], ~yuio.parse.LenGt(0)] 

49 

50 Non-empty frozenset. 

51 

52.. type:: NonEmptyDict 

53 :canonical: typing.Annotated[dict[K, V], ~yuio.parse.LenGt(0)] 

54 

55 Non-empty dict. 

56 

57.. type:: Pair 

58 :canonical: typing.Annotated[tuple[K, V], ~yuio.parse.Tuple(delimiter=":")] 

59 

60 Colon-separated pair of values. 

61 

62.. type:: Path 

63 :canonical: pathlib.Path 

64 

65 Filepath. 

66 

67.. type:: NonExistentPath 

68 :canonical: typing.Annotated[Path, ~yuio.parse.NonExistentPath] 

69 

70 Filepath not pointing to an existing file or directory. 

71 

72.. type:: ExistingPath 

73 :canonical: typing.Annotated[Path, ~yuio.parse.ExistingPath] 

74 

75 Filepath pointing to an existing file or directory. 

76 

77.. type:: File 

78 :canonical: typing.Annotated[Path, ~yuio.parse.File] 

79 

80 Filepath pointing to an existing regular file. 

81 

82.. type:: Dir 

83 :canonical: typing.Annotated[Path, ~yuio.parse.Dir] 

84 

85 Filepath pointing to an existing directory. 

86 

87.. type:: GitRepo 

88 :canonical: typing.Annotated[Path, ~yuio.parse.GitRepo] 

89 

90 Filepath pointing to an existing directory that has ``.git`` sub-directory. 

91 

92.. type:: TimeDelta 

93 :canonical: ~datetime.timedelta 

94 

95 Time delta. 

96 

97.. type:: PosTimeDelta 

98 :canonical: typing.Annotated[TimeDelta, ~yuio.parse.Gt(~datetime.timedelta(0))] 

99 

100 Positive time delta. 

101 

102.. type:: NonNegTimeDelta 

103 :canonical: typing.Annotated[TimeDelta, ~yuio.parse.Ge(~datetime.timedelta(0))] 

104 

105 Non-negative time delta. 

106 

107.. type:: Seconds 

108 :canonical: typing.Annotated[~datetime.timedelta, ~yuio.parse.Seconds()] 

109 

110 Timedelta that's parsed from int as number of seconds. 

111 

112.. type:: PosSeconds 

113 :canonical: typing.Annotated[Seconds, ~yuio.parse.Gt(~datetime.timedelta(0))] 

114 

115 Positive number of seconds. 

116 

117.. type:: NonNegSeconds 

118 :canonical: typing.Annotated[Seconds, ~yuio.parse.Ge(~datetime.timedelta(0))] 

119 

120 Non-negative number of seconds. 

121 

122 

123Re-imports 

124---------- 

125 

126.. type:: JsonValue 

127 :no-index: 

128 

129 Alias of :obj:`yuio.json_schema.JsonValue`. 

130 

131.. type:: SecretString 

132 :no-index: 

133 

134 Alias of :obj:`yuio.secret.SecretString`. 

135 

136.. type:: SecretValue 

137 :no-index: 

138 

139 Alias of :obj:`yuio.secret.SecretValue`. 

140 

141""" 

142 

143from __future__ import annotations 

144 

145import datetime 

146import pathlib 

147 

148import yuio.parse 

149from yuio.json_schema import JsonValue 

150from yuio.secret import SecretString, SecretValue 

151 

152from typing import TYPE_CHECKING 

153 

154if TYPE_CHECKING: 

155 import typing_extensions as _t 

156else: 

157 from yuio import _typing as _t 

158 

159__all__ = [ 

160 "Dir", 

161 "ExistingPath", 

162 "File", 

163 "GitRepo", 

164 "JsonValue", 

165 "NonEmptyDict", 

166 "NonEmptyFrozenSet", 

167 "NonEmptyList", 

168 "NonEmptySet", 

169 "NonEmptyStr", 

170 "NonExistentPath", 

171 "NonNegFloat", 

172 "NonNegInt", 

173 "NonNegSeconds", 

174 "NonNegTimeDelta", 

175 "Pair", 

176 "Path", 

177 "PosFloat", 

178 "PosInt", 

179 "PosSeconds", 

180 "PosTimeDelta", 

181 "Seconds", 

182 "SecretString", 

183 "SecretValue", 

184 "TimeDelta", 

185] 

186 

187 

188T = _t.TypeVar("T") 

189K = _t.TypeVar("K") 

190V = _t.TypeVar("V") 

191 

192 

193PosInt: _t.TypeAlias = _t.Annotated[int, yuio.parse.Gt(0)] 

194""" 

195Positive int. 

196 

197""" 

198 

199NonNegInt: _t.TypeAlias = _t.Annotated[int, yuio.parse.Ge(0)] 

200""" 

201Non-negative int. 

202 

203""" 

204 

205PosFloat: _t.TypeAlias = _t.Annotated[float, yuio.parse.Gt(0)] 

206""" 

207Positive float. 

208 

209""" 

210 

211NonNegFloat: _t.TypeAlias = _t.Annotated[float, yuio.parse.Ge(0)] 

212""" 

213Non-negative float. 

214 

215""" 

216 

217NonEmptyStr: _t.TypeAlias = _t.Annotated[str, yuio.parse.LenGt(0)] 

218""" 

219Non-empty string. 

220 

221""" 

222 

223NonEmptyList: _t.TypeAlias = _t.Annotated[list[T], yuio.parse.LenGt(0)] 

224""" 

225Non-empty list. 

226 

227""" 

228 

229NonEmptySet: _t.TypeAlias = _t.Annotated[set[T], yuio.parse.LenGt(0)] 

230""" 

231Non-empty set. 

232 

233""" 

234 

235NonEmptyFrozenSet: _t.TypeAlias = _t.Annotated[frozenset[T], yuio.parse.LenGt(0)] 

236""" 

237Non-empty frozenset. 

238 

239""" 

240 

241NonEmptyDict: _t.TypeAlias = _t.Annotated[dict[K, V], yuio.parse.LenGt(0)] 

242""" 

243Non-empty dict. 

244 

245""" 

246 

247Pair: _t.TypeAlias = _t.Annotated[tuple[K, V], yuio.parse.Tuple(delimiter=":")] 

248""" 

249Colon-separated pair of values. 

250 

251""" 

252 

253Path: _t.TypeAlias = pathlib.Path 

254""" 

255Filepath. 

256 

257""" 

258 

259NonExistentPath: _t.TypeAlias = _t.Annotated[Path, yuio.parse.NonExistentPath()] 

260""" 

261Filepath not pointing to an existing file or directory. 

262 

263""" 

264 

265ExistingPath: _t.TypeAlias = _t.Annotated[Path, yuio.parse.ExistingPath()] 

266""" 

267Filepath pointing to an existing file or directory. 

268 

269""" 

270 

271File: _t.TypeAlias = _t.Annotated[Path, yuio.parse.File()] 

272""" 

273Filepath pointing to an existing regular file. 

274 

275""" 

276 

277Dir: _t.TypeAlias = _t.Annotated[Path, yuio.parse.Dir()] 

278""" 

279Filepath pointing to an existing directory. 

280 

281""" 

282 

283GitRepo: _t.TypeAlias = _t.Annotated[Path, yuio.parse.GitRepo()] 

284""" 

285Filepath pointing to an existing directory that has ``.git`` sub-directory. 

286 

287""" 

288 

289TimeDelta: _t.TypeAlias = datetime.timedelta 

290""" 

291Time delta. 

292 

293""" 

294 

295_TD_ZERO = datetime.timedelta() 

296 

297PosTimeDelta: _t.TypeAlias = _t.Annotated[ 

298 TimeDelta, yuio.parse.Gt(_TD_ZERO), yuio.parse.WithMeta(desc="HH:MM:SS") 

299] 

300""" 

301Positive time delta. 

302 

303""" 

304 

305NonNegTimeDelta: _t.TypeAlias = _t.Annotated[ 

306 TimeDelta, yuio.parse.Ge(_TD_ZERO), yuio.parse.WithMeta(desc="HH:MM:SS") 

307] 

308""" 

309Non-negative time delta. 

310 

311""" 

312 

313Seconds: _t.TypeAlias = _t.Annotated[datetime.timedelta, yuio.parse.Seconds()] 

314""" 

315Timedelta that's parsed from int as number of seconds. 

316 

317""" 

318 

319PosSeconds: _t.TypeAlias = _t.Annotated[Seconds, yuio.parse.Gt(_TD_ZERO)] 

320""" 

321Positive number of seconds. 

322 

323""" 

324 

325NonNegSeconds: _t.TypeAlias = _t.Annotated[Seconds, yuio.parse.Ge(_TD_ZERO)] 

326""" 

327Non-negative number of seconds. 

328 

329"""