An import script reads thousands of rows. A bad row should not stop the import, but it must not vanish silently either. Write a class Collector(*types) whose objects are context managers used once per row:
errors = Collector(ValueError)
for row in rows:
with errors:
import_one(row)
with errors:gives the collector itself toas, if one is written.- If the block raises an exception that is an instance of one of
types(subclasses included), the exception is stopped there and recorded, and the program continues after the block. - Any other exception is not recorded and continues to the caller as usual.
blockscounts thewithblocks entered so far (starting at0).messagesis the list of recorded errors, oldest first, each written as"<block>: <exception type name>: <exception text>", where<block>is the number of the block in which it happened (the first block is1) and the text isstr(exception).
Setup helpers that use a Collector in with blocks, available with Run: import_rows(rows), lookups(keys, table), not_mine() and quiet_run(n).
Examples
Input: import_rows(["ana, 31", "ben,x", "chen,40", "dev", "eli,200"])
Output: ([("ana", 31), ("chen", 40)],
["2: ValueError: invalid literal for int() with base 10: 'x'",
"4: ValueError: not enough values to unpack (expected 2, got 1)",
"5: ValueError: age out of range: 200"],
5)
Constraints
- At least one exception type is given.
- Up to
10**4blocks per collector.
Goals
- Write a class-based context manager with `__enter__` and `__exit__`
- Swallow only chosen exception types by returning `True` from `__exit__`
- Keep state across many uses of the same context manager