Problem 358107 · medium · Level 03 Linear Management & Searching

A Settings File with Continued Lines

py-text-data · splitlines · py-iterators · py-exceptions

A desktop app keeps its settings in a small text file. Write read_settings(text) that returns the settings as a dictionary of strings. The rules:

  • Lines may end with \n, \r\n or \r.
  • A line ending in a backslash \ continues on the next line: the backslash is removed and the two lines are joined with exactly one space (spaces around the join are dropped). A continued line may continue again.
  • After joining, blank lines and lines whose first non-space character is # or ; are ignored.
  • A line [name] starts a section. Settings before the first section have plain keys; inside a section the key is section.key. Section names and keys are lower-cased.
  • A setting is key = value, split at the first =; the key and value are stripped. A later setting with the same key replaces the earlier one.
  • Any other line, or a setting with an empty key, is an error: raise ValueError with a message that starts with line N: where N is the (1-based) number of the line where it starts.

The tests check errors with the helpers raises(fn, *args) and message(fn, *args), which return the name and the message of the exception raised (or None).

Examples

Input:  text = "theme = dark\n[Editor]\nFont = Mono 12\n; old: size = 10\ntabs = 4\n"
Output: {"theme": "dark", "editor.font": "Mono 12", "editor.tabs": "4"}

Input:  text = "path = /usr/bin \\\n    /opt/bin\r\nurl = a=b"
Output: {"path": "/usr/bin /opt/bin", "url": "a=b"}

Input:  raises(read_settings, "ok = 1\njust some words\n")
Output: "ValueError"      (the message starts with "line 2:")

Constraints

  • len(text) <= 10**6.
  • A backslash on the very last line is simply removed.

Goals

  • Split text into lines with `splitlines`, whatever the line endings
  • Join a line with the next one by pulling it from the iterator with `next`
  • Raise `ValueError` with the line number for a line that cannot be understood
Starting Python…