107

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?

AMC
  • 2,642
  • 7
  • 13
  • 35
CaioRamaglio
  • 1,197
  • 2
  • 6
  • 6
  • 2
    See also https://stackoverflow.com/q/4990718/20670 – Tim Pietzcker Mar 01 '19 at 16:25
  • 1
    Wikipedia has some good information on this--it's called [error hiding](https://en.wikipedia.org/wiki/Error_hiding). – John Szakmeister Mar 01 '19 at 16:28
  • 3
    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. – Adam Smith Mar 01 '19 at 16:30

2 Answers2

157

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

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • 4
    One example where you may want to catch every exception is when using databases. Catch all and do some cleanup. – Amit Tripathi Dec 05 '19 at 11:25
  • 2
    I believe multiprocessing is another example, to avoid stuck sub-processes adequately terminating the pool. – RomuloPBenedetti Mar 15 '20 at 20:50
  • You should consider context managers for both of these cases. – Adam Smith Mar 15 '20 at 20:57
  • 2
    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. – Oscar Benjamin May 19 '20 at 22:09
  • Another example is when a process is not important. For example, sending a notification. I don't want the flow of everything to stop if I fail to send a notification, so I catch it, log it, and continue – AbdulRahman AlHamali Feb 04 '21 at 16:10
  • @AbdulRahmanAlHamali don't you, though? If you get an exception that indicates an ephemeral network error, wouldn't you want to log and retry your notification rather than log and continue? – Adam Smith Feb 04 '21 at 17:33
  • 1
    @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 – AbdulRahman AlHamali Feb 05 '21 at 19:05
  • What this answer doesn't explain is why `except Exception:` raises a similar warning until you add a bare `raise` at the end of the block. Yet `except:`...`raise` still gives you the warning. In that context you almost certainly **do** want to catch the `KeyboardInterrupt`. Exception blocks ending in a bare raise are virtually always (a)logging and (b) cleaning up / rolling back. I wonder if there are other similar exceptions which are somehow dangerous to catch even with a bare raise at the end. – Philip Couling Aug 06 '21 at 09:39
  • Incidentally you only use a context manager where one has been implemented by the library. Plenty don't. And context managers don't commonly distinguish between success and failure. I've hit plenty of scenarios where I needed cleanup which *must not* be executed on success (unlike a SQL ROLLBACK). – Philip Couling Aug 06 '21 at 09:51
  • How can I find out what the exact exception name is? So as I can copy and paste it – DanielBell99 Mar 04 '22 at 10:18
  • 1
    @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" – Adam Smith Mar 05 '22 at 05:18
36

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.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263