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

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

119 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 return DottedKey([SingleKey(_k) for _k in k]) 

266 

267 

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

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

270 

271 :Example: 

272 

273 >>> value("1") 

274 1 

275 >>> value("true") 

276 True 

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

278 [1, 2, 3] 

279 """ 

280 parser = Parser(raw) 

281 v = parser._parse_value() 

282 if not parser.end(): 

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

284 return v 

285 

286 

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

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

289 

290 :Example: 

291 

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

293 (Key('foo'), 1) 

294 """ 

295 return Parser(src)._parse_key_value() 

296 

297 

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

299 """Create a whitespace from a string.""" 

300 return Whitespace(src, fixed=True) 

301 

302 

303def nl() -> Whitespace: 

304 """Create a newline item.""" 

305 return ws("\n") 

306 

307 

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

309 """Create a comment item.""" 

310 return Comment(Trivia(comment_ws=" ", comment="# " + string)) 

311 

312 

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

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

315 if the value can't otherwise be converted. 

316 

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

318 

319 Example: 

320 @register_encoder 

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

322 if isinstance(obj, CustomDict): 

323 tbl = table() 

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

325 # Pass along parameters when encoding nested values 

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

327 return tbl 

328 raise ConvertError("Not a CustomDict") 

329 """ 

330 CUSTOM_ENCODERS.append(encoder) 

331 return encoder 

332 

333 

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

335 """Unregister a custom encoder.""" 

336 with contextlib.suppress(ValueError): 

337 CUSTOM_ENCODERS.remove(encoder)