Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/tomlkit/api.py: 52%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

124 statements  

1from __future__ import annotations 

2 

3import contextlib 

4import datetime as _datetime 

5 

6from collections.abc import Iterable 

7from collections.abc import Mapping 

8from typing import IO 

9from typing import TYPE_CHECKING 

10from typing import Any 

11from typing import TypeVar 

12 

13from tomlkit._utils import parse_rfc3339 

14from tomlkit.container import Container 

15from tomlkit.exceptions import UnexpectedCharError 

16from tomlkit.items import CUSTOM_ENCODERS 

17from tomlkit.items import AoT 

18from tomlkit.items import Array 

19from tomlkit.items import Bool 

20from tomlkit.items import Comment 

21from tomlkit.items import Date 

22from tomlkit.items import DateTime 

23from tomlkit.items import DottedKey 

24from tomlkit.items import Float 

25from tomlkit.items import InlineTable 

26from tomlkit.items import Integer 

27from tomlkit.items import Item as _Item 

28from tomlkit.items import Key 

29from tomlkit.items import SingleKey 

30from tomlkit.items import String 

31from tomlkit.items import StringType as _StringType 

32from tomlkit.items import Table 

33from tomlkit.items import Time 

34from tomlkit.items import Trivia 

35from tomlkit.items import Whitespace 

36from tomlkit.items import item as item 

37from tomlkit.parser import Parser 

38from tomlkit.toml_document import TOMLDocument as TOMLDocument 

39 

40 

41if TYPE_CHECKING: 

42 from tomlkit.items import Encoder 

43 

44 E = TypeVar("E", bound=Encoder) 

45 

46 

47def loads(string: str | bytes) -> TOMLDocument: 

48 """ 

49 Parses a string into a TOMLDocument. 

50 

51 Alias for parse(). 

52 """ 

53 return parse(string) 

54 

55 

56def dumps(data: Mapping[str, Any], sort_keys: bool = False) -> str: 

57 """ 

58 Dumps a TOMLDocument into a string. 

59 """ 

60 if isinstance(data, (Table, InlineTable, Container)): 

61 if not sort_keys: 

62 return data.as_string() 

63 

64 return item(data, _sort_keys=True).as_string() 

65 

66 if isinstance(data, Mapping): 

67 return item(dict(data), _sort_keys=sort_keys).as_string() 

68 

69 try: 

70 # mapping-like wrappers (e.g. dotty_dict's Dotty) delegate 

71 # ``as_string`` to the document they wrap; rendering it directly 

72 # preserves the original layout, which re-encoding through a plain 

73 # dict would lose 

74 return data.as_string() # type: ignore[attr-defined] 

75 except AttributeError as ex: 

76 msg = f"Expecting Mapping or TOML Table or Container, {type(data)} given" 

77 raise TypeError(msg) from ex 

78 

79 

80def load(fp: IO[str] | IO[bytes]) -> TOMLDocument: 

81 """ 

82 Load toml document from a file-like object. 

83 """ 

84 return parse(fp.read()) 

85 

86 

87def dump(data: Mapping[str, Any], fp: IO[str], *, sort_keys: bool = False) -> None: 

88 """ 

89 Dump a TOMLDocument into a writable file stream. 

90 

91 :param data: a dict-like object to dump 

92 :param sort_keys: if true, sort the keys in alphabetic order 

93 

94 :Example: 

95 

96 >>> with open("output.toml", "w") as fp: 

97 ... tomlkit.dump(data, fp) 

98 """ 

99 fp.write(dumps(data, sort_keys=sort_keys)) 

100 

101 

102def parse(string: str | bytes) -> TOMLDocument: 

103 """ 

104 Parses a string or bytes into a TOMLDocument. 

105 """ 

106 return Parser(string).parse() 

107 

108 

109def document() -> TOMLDocument: 

110 """ 

111 Returns a new TOMLDocument instance. 

112 """ 

113 return TOMLDocument() 

114 

115 

116# Items 

117def integer(raw: str | int) -> Integer: 

118 """Create an integer item from a number or string.""" 

119 return item(int(raw)) 

120 

121 

122def float_(raw: str | float) -> Float: 

123 """Create an float item from a number or string.""" 

124 return item(float(raw)) 

125 

126 

127def boolean(raw: str | bool) -> Bool: 

128 """Turn `true` or `false` into a boolean item.""" 

129 return item(raw == "true" if isinstance(raw, str) else raw) 

130 

131 

132def string( 

133 raw: str, 

134 *, 

135 literal: bool = False, 

136 multiline: bool = False, 

137 escape: bool = True, 

138) -> String: 

139 """Create a string item. 

140 

141 By default, this function will create *single line basic* strings, but 

142 boolean flags (e.g. ``literal=True`` and/or ``multiline=True``) 

143 can be used for personalization. 

144 

145 For more information, please check the spec: `<https://toml.io/en/v1.0.0#string>`__. 

146 

147 Common escaping rules will be applied for basic strings. 

148 This can be controlled by explicitly setting ``escape=False``. 

149 Please note that, if you disable escaping, you will have to make sure that 

150 the given strings don't contain any forbidden character or sequence. 

151 """ 

152 type_ = _StringType.select(literal, multiline) 

153 return String.from_raw(raw, type_, escape) 

154 

155 

156def date(raw: str) -> Date: 

157 """Create a TOML date.""" 

158 value = parse_rfc3339(raw) 

159 if not isinstance(value, _datetime.date): 

160 raise ValueError("date() only accepts date strings.") 

161 

162 return item(value) 

163 

164 

165def time(raw: str) -> Time: 

166 """Create a TOML time.""" 

167 value = parse_rfc3339(raw) 

168 if not isinstance(value, _datetime.time): 

169 raise ValueError("time() only accepts time strings.") 

170 

171 return item(value) 

172 

173 

174def datetime(raw: str) -> DateTime: 

175 """Create a TOML datetime.""" 

176 value = parse_rfc3339(raw) 

177 if not isinstance(value, _datetime.datetime): 

178 raise ValueError("datetime() only accepts datetime strings.") 

179 

180 return item(value) 

181 

182 

183def array(raw: str = "[]") -> Array: 

184 """Create an array item for its string representation. 

185 

186 :Example: 

187 

188 >>> array("[1, 2, 3]") # Create from a string 

189 [1, 2, 3] 

190 >>> a = array() 

191 >>> a.extend([1, 2, 3]) # Create from a list 

192 >>> a 

193 [1, 2, 3] 

194 """ 

195 v = value(raw) 

196 if not isinstance(v, Array): 

197 raise ValueError(f"Expected an array, got {type(v)}") 

198 return v 

199 

200 

201def table(is_super_table: bool | None = None) -> Table: 

202 """Create an empty table. 

203 

204 :param is_super_table: if true, the table is a super table 

205 

206 :Example: 

207 

208 >>> doc = document() 

209 >>> foo = table(True) 

210 >>> bar = table() 

211 >>> bar.update({'x': 1}) 

212 >>> foo.append('bar', bar) 

213 >>> doc.append('foo', foo) 

214 >>> print(doc.as_string()) 

215 [foo.bar] 

216 x = 1 

217 """ 

218 return Table(Container(), Trivia(), False, is_super_table) 

219 

220 

221def inline_table() -> InlineTable: 

222 """Create an inline table. 

223 

224 :Example: 

225 

226 >>> table = inline_table() 

227 >>> table.update({'x': 1, 'y': 2}) 

228 >>> print(table.as_string()) 

229 {x = 1, y = 2} 

230 """ 

231 return InlineTable(Container(), Trivia(), new=True) 

232 

233 

234def aot() -> AoT: 

235 """Create an array of table. 

236 

237 :Example: 

238 

239 >>> doc = document() 

240 >>> aot = aot() 

241 >>> aot.append(item({'x': 1})) 

242 >>> doc.append('foo', aot) 

243 >>> print(doc.as_string()) 

244 [[foo]] 

245 x = 1 

246 """ 

247 return AoT([]) 

248 

249 

250def key(k: str | Iterable[str]) -> Key: 

251 """Create a key from a string. When a list of string is given, 

252 it will create a dotted key. 

253 

254 :Example: 

255 

256 >>> doc = document() 

257 >>> doc.append(key('foo'), 1) 

258 >>> doc.append(key(['bar', 'baz']), 2) 

259 >>> print(doc.as_string()) 

260 foo = 1 

261 bar.baz = 2 

262 """ 

263 if isinstance(k, str): 

264 return SingleKey(k) 

265 keys = [SingleKey(_k) for _k in k] 

266 if len(keys) == 1: 

267 return keys[0] 

268 return DottedKey(keys) 

269 

270 

271def value(raw: str) -> _Item: 

272 """Parse a simple value from a string. 

273 

274 :Example: 

275 

276 >>> value("1") 

277 1 

278 >>> value("true") 

279 True 

280 >>> value("[1, 2, 3]") 

281 [1, 2, 3] 

282 """ 

283 parser = Parser(raw) 

284 v = parser._parse_value() 

285 if not parser.end(): 

286 raise parser.parse_error(UnexpectedCharError, char=parser._current) 

287 return v 

288 

289 

290def key_value(src: str) -> tuple[Key, _Item]: 

291 """Parse a key-value pair from a string. 

292 

293 :Example: 

294 

295 >>> key_value("foo = 1") 

296 (Key('foo'), 1) 

297 """ 

298 return Parser(src)._parse_key_value() 

299 

300 

301def ws(src: str) -> Whitespace: 

302 """Create a whitespace from a string.""" 

303 return Whitespace(src, fixed=True) 

304 

305 

306def nl() -> Whitespace: 

307 """Create a newline item.""" 

308 return ws("\n") 

309 

310 

311def comment(string: str) -> Comment: 

312 """Create a comment item. 

313 

314 A multiline string produces one ``#``-prefixed line per line so that the 

315 result is still valid TOML. 

316 """ 

317 lines = string.split("\n") 

318 rendered = "\n".join(f"# {line}" if line else "#" for line in lines) 

319 return Comment(Trivia(comment_ws=" ", comment=rendered)) 

320 

321 

322def register_encoder(encoder: E) -> E: 

323 """Add a custom encoder, which should be a function that will be called 

324 if the value can't otherwise be converted. 

325 

326 The encoder should return a TOMLKit item or raise a ``ConvertError``. 

327 

328 Example: 

329 @register_encoder 

330 def encode_custom_dict(obj, _parent=None, _sort_keys=False): 

331 if isinstance(obj, CustomDict): 

332 tbl = table() 

333 for key, value in obj.items(): 

334 # Pass along parameters when encoding nested values 

335 tbl[key] = item(value, _parent=tbl, _sort_keys=_sort_keys) 

336 return tbl 

337 raise ConvertError("Not a CustomDict") 

338 """ 

339 CUSTOM_ENCODERS.append(encoder) 

340 return encoder 

341 

342 

343def unregister_encoder(encoder: Encoder) -> None: 

344 """Unregister a custom encoder.""" 

345 with contextlib.suppress(ValueError): 

346 CUSTOM_ENCODERS.remove(encoder)