== An example of a subtle over-broad _try_ in Python Today I wrote some code to winnow a list of users to 'real' users with live home directories that looks roughly like the following: .pn prewrap on > for uname, hdir in userlist: > try: > st = os.stat(hdir) > if not stat.S_ISDIR(st.st_mode) or \ > stat.S_IMODE(st.st_mode) == 0: > continue > # looks good: > print uname > except EnvironmentError: > # accept missing homedir; might be a > # temporarily missing NFS mount, we > # can't tell. > print uname This code has a relatively subtle flaw because I've accidentally written [[an over-broad exception catcher BroadTrys]] here. As suggested by the comment, when I wrote this code I intended the _try_ block to catch the case where the _os.stat_ failed. The flaw here is that _print_ itself does IO (of course) and so can raise an IO exception. Since I have the _print_ inside my _try_ block, a _print_-raised IO exception will get caught by it too. You might think that this is harmless because the _except_ will re-do the _print_ and thus presumably immediately have the exception raised again. This contains two assumptions: that the exception will be raised again and that if it isn't, the output is in a good state (as opposed to, say, having written only partial output before an error happened). Neither are entirely sure things and anyways, we shouldn't be relying on this sort of thing when it's really easy to fix. Since both branches of the exception end up at the same _print_, all we have to do is move it outside the _try:_ block entirely (the _except_ case then becomes just '_pass_'). (My view is that _print_ failing is unusual enough that I'm willing to have the program die with a stack backtrace, partly because this is an internal tool. If that's not okay you'd need to put the _print_ in its own _try_ block and then do something if it failed, or have an overall _try_ block around the entire operation to catch otherwise unexpected _EnvironmentError_ exceptions.) The root cause here is that I wasn't thinking of _print_ as something that does IO that can throw exceptions. Basic printing is sufficiently magical that it feels different and more ordinary, so it's easy to forget that this is a possibility. It's especially easy to overlook because it's extremely uncommon for _print_ to fail in most situations ([[although there are exceptions SignalExceptionSurprise]], [[especially in Python 3 StringsPython2And3]]). You can also attribute this to a failure to minimize what's done inside _try_ blocks to only things that absolutely have to be there, as opposed to things that are just kind of convenient for the flow of code. As a side note, one of the things that led to this particular case is that I changed my mind about what should happen when the _os.stat()_ failed because I realized that failure might have legitimate causes instead of being a sign of significant problems with an account that should cause it to be skipped. When I changed my mind I just did a quick change to what the _except_ block did instead of totally revising the overall code, partly because this is a small quick program instead of a big system.