Parse TOML from a string.
(s: str, /, *, parse_float: ParseFloat = float)
| 135 | |
| 136 | |
| 137 | def loads(s: str, /, *, parse_float: ParseFloat = float) -> dict[str, Any]: |
| 138 | """Parse TOML from a string.""" |
| 139 | |
| 140 | # The spec allows converting "\r\n" to "\n", even in string |
| 141 | # literals. Let's do so to simplify parsing. |
| 142 | try: |
| 143 | src = s.replace("\r\n", "\n") |
| 144 | except (AttributeError, TypeError): |
| 145 | raise TypeError( |
| 146 | f"Expected str object, not '{type(s).__qualname__}'" |
| 147 | ) from None |
| 148 | pos = 0 |
| 149 | out = Output() |
| 150 | header: Key = () |
| 151 | parse_float = make_safe_parse_float(parse_float) |
| 152 | |
| 153 | # Parse one statement at a time |
| 154 | # (typically means one line in TOML source) |
| 155 | while True: |
| 156 | # 1. Skip line leading whitespace |
| 157 | pos = skip_chars(src, pos, TOML_WS) |
| 158 | |
| 159 | # 2. Parse rules. Expect one of the following: |
| 160 | # - end of file |
| 161 | # - end of line |
| 162 | # - comment |
| 163 | # - key/value pair |
| 164 | # - append dict to list (and move to its namespace) |
| 165 | # - create dict (and move to its namespace) |
| 166 | # Skip trailing whitespace when applicable. |
| 167 | try: |
| 168 | char = src[pos] |
| 169 | except IndexError: |
| 170 | break |
| 171 | if char == "\n": |
| 172 | pos += 1 |
| 173 | continue |
| 174 | if char in KEY_INITIAL_CHARS: |
| 175 | pos = key_value_rule(src, pos, out, header, parse_float) |
| 176 | pos = skip_chars(src, pos, TOML_WS) |
| 177 | elif char == "[": |
| 178 | try: |
| 179 | second_char: str | None = src[pos + 1] |
| 180 | except IndexError: |
| 181 | second_char = None |
| 182 | out.flags.finalize_pending() |
| 183 | if second_char == "[": |
| 184 | pos, header = create_list_rule(src, pos, out) |
| 185 | else: |
| 186 | pos, header = create_dict_rule(src, pos, out) |
| 187 | pos = skip_chars(src, pos, TOML_WS) |
| 188 | elif char != "#": |
| 189 | raise TOMLDecodeError("Invalid statement", src, pos) |
| 190 | |
| 191 | # 3. Skip comment |
| 192 | pos = skip_comment(src, pos) |
| 193 | |
| 194 | # 4. Expect end of line or end of file |
searching dependent graphs…