Patterns ======== Optional error handling ----------------------- Some functions take an ``error`` argument that direct the function to return :obj:`None` instead of raising an exception. New functions that do this should be split into multiple functions. If a function that raises (or allows) optional exceptions is annotated as returning an ``Optional`` value, every caller is expected to check the result, even though the result is `not` optional when ``error=False`` is passed. Example 1: Function raises its own exceptions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block: py def new_routine(val: gdb.Value) -> str: if some_condition: raise RuntimeError("something bad happened") return val.string() def new_routine_safe(val: gdb.Value) -> Optional[str]: try: return new_routine(val) except RuntimeError: return None Example 2: Function calls functions that raise optional exceptions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block: py def some_existing_routine(val: gdb.Value, error: bool = True) -> Optional[str]: if some_condition: if error: raise RuntimeError("something bad happened") return None return val.string() def new_routine(val: gdb.Value) -> str: print("do something") ret = some_existing_routine(val) if ret is None: raise RuntimeError("some_existing_routine can't return None") return ret def new_routine_safe(val: gdb.Value) -> str: return some_existing_routine(val, False)