Study notes · 10% of the exam

Exceptions, Logging and Testing

Know exactly how try/except/else/finally behave, how exceptions chain and group, how logging decides what to emit, and how pytest and unittest.mock work so tests catch real bugs instead of hiding them.

Key points

  1. 1

    except Exception misses BaseException subclasses (KeyboardInterrupt, SystemExit, GeneratorExit); a bare except: catches them all, which can swallow sys.exit() and Ctrl+C.

  2. 2

    finally always runs. A return or exception inside it replaces the pending result or exception, so keep cleanup code simple and never return from it.

  3. 3

    raise X from e sets __cause__ ("direct cause"), implicit raising sets __context__ ("During handling…"), and from None hides the context while still storing it.

  4. 4

    except* (3.11+) can run several clauses for one ExceptionGroup, always binds a group, re-raises unmatched leaves as a new group, and forbids return/break/continue inside the block.

  5. 5

    Logging: records pass the logger level, then each handler level, then propagate to ancestor handlers. basicConfig is ignored once handlers exist unless force=True. Use lazy %-style arguments.

  6. 6

    pytest: fixtures with yield give setup/teardown, scopes control lifetime, parametrize multiplies, raises(match=) is a regex search, and approx compares floats.

  7. 7

    unittest.mock: patch where the name is looked up, prefer spec/autospec, and remember side_effect beats return_value and raises StopIteration when an iterable runs out.

Common traps

  • The name bound by except ... as e is deleted when the block ends, even if e existed before.

  • assert statements disappear under python -O, so never use them for validation.

  • Patching module.attr does nothing for code that already did from module import attr; patch the importing module instead.

Test yourself on Exceptions, Logging and Testing

Ten questions, with the answer and explanation after each one.