140

I tried making a function to check if an image is displayed on the screen using PyAutoGui and came up with this:

def check_image_on_screen(image):
    try:
        pyautogui.locateCenterOnScreen(image)
        return True
    except:
        return False

And it works fine, but PyCharm tells me I shouldn't leave except bare. What is the problem with leaving it like this? Is there a more appropriate way of creating the same function?

3
  • 2
    See also stackoverflow.com/q/4990718/20670 Commented Mar 1, 2019 at 16:25
  • 1
    Wikipedia has some good information on this--it's called error hiding. Commented Mar 1, 2019 at 16:28
  • 5
    I'm not sure this is a duplicate of that. This is asking "Why not bare except" while that one is asking "How do I bare except." A good answer for the latter probably answers the former, but that doth not a duplicate make. Commented Mar 1, 2019 at 16:30

3 Answers 3

200

Bare except will catch exceptions you almost certainly don't want to catch, including KeyboardInterrupt (the user hitting Ctrl+C) and Python-raised errors like SystemExit

If you don't have a specific exception you're expecting, at least except Exception, which is the base type for all "Regular" exceptions.


That being said: you use except blocks to recover from known failure states. An unknown failure state is usually irrecoverable, and it is proper behavior to fatally exit in those states, which is what the Python interpreter does naturally with an uncaught exception.

Catch everything you know how to handle, and let the rest propagate up the call stack to see if something else can handle it. In this case the error you're expecting (per the docs) is pyautogui.ImageNotFoundException

Sign up to request clarification or add additional context in comments.

11 Comments

One example where you may want to catch every exception is when using databases. Catch all and do some cleanup.
I believe multiprocessing is another example, to avoid stuck sub-processes adequately terminating the pool.
Those are both examples where you might want to use try/finally rather than try/except. Using finally means that you can guarantee cleanup but the exception will still be propagated afterwards.
@AdamSmith indeed, we do retry the notification, but if it just keeps failing. I don't want that to stop everything. We realized that in the Great Slack Failure of 2021, where deployments were failing simply because they couldn't send a Slack notification
@StressedBoi_69420 The exception should be visible in the stack trace. For example try doing [][0] and observe the stack says "IndexError," or {"ok":None}['nope'] and observe the stack says "KeyError"
|
41

Basically, you're not taking advantage of the language to help you find problems. If you used except Exception as ex: you could do something like log the exception and know exactly what happened.

7 Comments

No. The whole point here is why it's bad to use a bare except.
I mean to say: Logging is one of the good times to use a bare except, as called out in PEP-8 under "Programming Recommendations": A good rule of thumb is to limit use of bare ‘except’ clauses to two cases: 1. If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred. ... Logging is not a good example of why it's bad to use a bare except.
Yeah, that's plausible, and certainly okay for class assignments and the like. But in production-quality code, it means you're concealing the issue from the code at run time, and that's unwise. I can't even begin to count how many times I saw a fault that was either ignored completely because, hey, we can just log it, or turned into a program that failed by a generic exception propagated to the top level.
With a subsiquent bare raise, there's no code path that would allow this to conceal the issue from code. And python is not a 50 year old language. And I've been managing production code quite a while too. My comments are not about experience but logical possibility in the language.
Yes, the exception gets logged and then gets propagated back up the stack of try blocks which may result in the exception getting handled by the main thread’s exception handler and so crashing the program. logging isn’t supposed to interfere with the flow of execution, just report on progress.
|
9

Removing bare except: is sometimes a good idea but not always. Beware about Pycharm's warning on this.

PyCharm is reporting a warning from pycodestyle which cannot enforce the rule correctly so it enforces the rule incorrectly. See issue: E722: (bare excepts) too strict (reraise)

As a general rule:

  • bare except for cleanup is the nearly always the right thing to do when finally: won't do.
  • bare except for logging often the right thing to do, but depends on whether you want to see logging of deliberate exit.

In both cases you MUST re-raise with a subsiquent bare raise.

PEP 8 Says:

A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException:). A good rule of thumb is to limit use of bare ‘except’ clauses to two cases:

  1. If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
  2. If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise. try...finally can be a better way to handle this case.

General Advice

Always re-raise a bare except

Good:

try:
    do_something()
except:
    logging.exception("Failed")
    raise

Bad

try:
    do_something()
except:
    logger.exception("Failed")

💥 This just ate a Ctrl-C or SystemExit

Make sure you always clean up

In cases were you need to clean up on error (and only on error), bare except is better

Good

file = open("my_file.txt", "w")
try:
    with file:
        file.write("something")
except:
    os.unlink("my_file.txt")
    raise

Bad

file = open("my_file.txt", "w")
try:
    with file:
        file.write("something")
except Exception:
    os.unlink("my_file.txt")
    raise

💥 If the user hits CTRL-C at the keyboard at the wrong moment, the file gets left behind.

2 Comments

Thank you for raising my awareness that I do not need to use open explicitly on the same line as with. Obviously valid syntax, but I think habits have replaced thought.
@Galen yes on that note it is worth mentioning here there is a known danger even with it on the same line. Breaking it apart makes it no worse.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.