3
with suppress(ValueError):
    while test_condition:
        biglist.remove(222) # element that doesn't exist, raises error. but we dont care abt this error.
        # LINE-A: more remove kind of calls where we are dont care abt ValueError(s) raised
        # LINE-B: ...
        # ...
        # LINE-Z: ...

# LINE-1: some statement..
# some more statements...

With contextlib.suppress, the while loop is stopped on the first exception that occurs and execution jumps to LINE-1. Is there an alternative construct or facility in Python where we can ignore multiple errors that happen within a context and continue execution within the context from LINE-A to LINE-Z without interruption. That is, if an exception happens at LINE-A, execution continues to LINE-B instead of jumping to LINE-1.

Using multiple try-except-finally to cover each line from LINE-A to LINE-Z is not really a clean option for me, as it severely affects readability.

try:
    #LINE-A...
except ValueError:
    pass
finally:
    try:
        #LINE-B...
     except ValueError:
        pass
     finally:
        #....

Wrapping each of LINE-A to LINE-Z with their own with suppress is one possibility but has less readability, so I am asking if there are alternatives that are more

2020
  • 2,821
  • 2
  • 23
  • 40
  • 1
    Related(?): [General decorator to wrap try except in python?](https://stackoverflow.com/questions/15572288/general-decorator-to-wrap-try-except-in-python) ... dupe? – wwii Dec 05 '19 at 19:40
  • Are all of the statements (LINE-A through LINE-Z) single line statements? Or do they contain loops/with statements/other multi-line blocks? As an aside- there is a way to do this in visual basic using the `On Error Resume Next` statement which ignores any and all errors following. – SyntaxVoid Dec 05 '19 at 19:42
  • 1
    I don't like the name, but it looks like this can help you: https://github.com/ajalt/fuckitpy. – SyntaxVoid Dec 05 '19 at 19:49
  • 1
    More related... [Prevent 'try' to catch an exception and pass to the next line in python](https://stackoverflow.com/questions/46702575/prevent-try-to-catch-an-exception-and-pass-to-the-next-line-in-python) ... [How to prevent try catching every possible line in python?](https://stackoverflow.com/questions/10898873/how-to-prevent-try-catching-every-possible-line-in-python) .. there are more – wwii Dec 05 '19 at 19:53
  • @SyntaxVoidsupportsMonica: The LINEs could be anything...including loops and multi-line blocks not necessarily single line statements. Thanks for the links. They are quite helpful, if am dealing only with single-line function calls or expressions. – 2020 Dec 05 '19 at 20:12
  • 1
    could you refactor your lines of actions into a list of callables, perhaps with lambdas? then you could just call an execution context function in a loop with a try/except wrapper. thats what i would aim for. hard to tell with just your chosen remove(200) example if that makes any sense though. – JL Peyret Dec 07 '19 at 10:35
  • Yes, I could refactor them that way, @JLPeyret. But I was looking for a way in python which wouldnt require any special coding of each line in the loop but wraps the intent in the context and leaves the lines inside the context to be unmodified wrt their association with context, similar to how the code inside the `with suppress` context is not special code but just regular code. – 2020 Dec 08 '19 at 16:07

1 Answers1

1

What about this?

def do_it(func, *args,suppress_exc=None, **kwargs):
    params = locals().copy()
    suppress_exc= suppress_exc or (ValueError,)
    try:
        func(*args, **kwargs)
        print("\nsweet  %s worked" % (params))
        return 0
    except suppress_exc as e: #pragma: no cover
        print("\nbummer %s failed" % (params))
        return e


biglist = [200, 300, 400]

while True:

    if not do_it(biglist.remove, 201):
        break

    if not do_it(biglist.pop, 6, suppress_exc=(IndexError,)):
        break

    if not do_it(biglist.remove, 200):
        break

    if not do_it(biglist.remove, 300):
        break

    if not do_it(biglist.remove, 400):
        break

print("done:biglist:%s" % (biglist))

out:

bummer {'kwargs': {}, 'args': (201,), 'suppress_exc': None, 'func': <built-in method remove of list object at 0x106093ec8>} failed

bummer {'kwargs': {}, 'args': (6,), 'suppress_exc': (<class 'IndexError'>,), 'func': <built-in method pop of list object at 0x106093ec8>} failed

sweet  {'kwargs': {}, 'args': (200,), 'suppress_exc': None, 'func': <built-in method remove of list object at 0x106093ec8>} worked
done:biglist:[300, 400]
JL Peyret
  • 10,917
  • 2
  • 54
  • 73
  • Awesome suggestion ! Looks like I do have to touch each line inside the loop and make it special and aware about what is intended. That is, modify my regular code to make it aware of the special handling being done in each line. But thanks anyways. For lack of a direct method to achieve what I wanted, I will accept this suggestion. – 2020 Dec 08 '19 at 16:09