We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← From Everyday Python to Production Code step 5 of 223
Placement 3/6: Turn Parse Errors into Your Own Exception
Solve this without the hints and you can skim the error-handling track.
You are reading a config file of key=number lines. When a line is bad, the
caller should get one exception type that means "bad config line", whatever
went wrong underneath. The starter gives you that type, ConfigError. Code
that catches it knows the config is at fault, not some unrelated bug.
When the number does not parse, int() raises ValueError. Keep that error
attached to your ConfigError with exception chaining:
except ValueError as exc:
raise ConfigError(line) from exc
from exc stores the original exception in the new one's __cause__
attribute, and the traceback shows both.
Parse one line
Write parse_line(line: str) -> tuple[str, int]. Split line at the first
=, and strip whitespace from each part. Then check, in this order:
- If there is no
=, or the key is empty after stripping, raiseConfigError(line)withoutfrom, so__cause__isNone. - Convert the value with
int(value). If that raisesValueError, raiseConfigError(line) from exc. - Otherwise return the stripped key and the integer.
Always pass the original, unstripped line to ConfigError. Any non-empty key
is fine. Don't add support for comments or any other syntax.
int() accepts a sign, leading zeros and underscores between digits, so
"n=+0" gives ("n", 0) and "n=1_000" gives ("n", 1000). An empty value,
"1.5" and "1=2" all fail to convert. "=bad" fails the key check first,
so it has no cause.
ConfigError is a subclass of ValueError. Put the try around the int()
call alone. A wider try would catch the ConfigError you raise in the key
check and chain it to a second one.
Collect the results
Write solve(lines: list[str]) -> dict[str, list[str]]. Call parse_line on
every line, catch ConfigError for that line, and carry on with the next.
Catch only ConfigError, so a real bug still shows up. Return two lists that
keep the input order and any duplicates:
"ok": onef"{key}={value}"per good line, using the parsed values."errors": onef"{line}|ConfigError|{cause}"per bad line.lineis the raw line, spaces and all, with nothing escaped.causeis the class name ofexc.__cause__, or"-"when it isNone.
solve([" n=+0 ", "bad=x", "missing", "ok=3"])
# {"ok": ["n=0", "ok=3"],
# "errors": ["bad=x|ConfigError|ValueError", "missing|ConfigError|-"]}
An empty list returns {"ok": [], "errors": []}.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.