Re: [Python-ideas] [Python-Dev] OSError.errno => exception hierarchy?

[Moving to python-ideas] On Thu, Apr 2, 2009 at 9:12 AM, Gustavo Carneiro <gjcarneiro@gmail.com> wrote:
Note, these words are pretty offensive (or perhaps passive-aggressive). How would you respond if some Perl hacker said "I was expecting that by now, Python 3.0, Python would have dropped the whitespace bug."
Again, offensive words -- makes you sound like you are so much smarter than us.
Again poor choice of words. Note the leading question: you don't even consider the possibility that it's a bad idea. Compare "When did you stop beating your wife?"
This would cause more platform problems than we already have. Consider an errno (EWIN, mapped to OSWinError in your proposal) that exists only on Windows, and another (ELIN, OSLinError) that exists only on Linux. Now suppose you have to catch both of them. If you write your code like this: try: ... except OSWinError: ... except OSLinError: ... then on Linux, if OSLinError is raised, the "except OSWinError:" clause will raise a NameError because that exception isn't defined, and you'll never reach the "except OSLinError:" clause. If you reverse the clauses you have the same problem on Windows. While you would have the same problem if you tried to do something like "if e.errno == errno.EWIN:" on Linux, it's easier to circumvent -- one of the many ways to do so is to write "if errno.errorcode[e.errno] == 'EWIN':" instead..
Accidental (my phone's experimental gmail client is missing a reply-all). I'm adding python-ideas since that's where it belongs. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

2009/4/2 Guido van Rossum <guido@python.org>
Sorry. I suck at this. I think I'm too impatient (read: time constrained) to be polite :P
Maybe I didn't express myself very well. By "no will to do it" I meant "no interest to do it". If you thought it was a bad idea you would have no interest in doing it. To be frank, what I thought most likely was that, with all the refactoring going on in Python 3, this issue, which was an obvious cleanup to me (but now I realize it is not obvious at all to everyone else), was overlooked because there were bigger problems to solve. So there are usually only three reasons why something is not done: 1- It's a bad idea; 2- No one thought of it; 3- It's a good and known idea, but there was no manpower to do it. I was betting more on 2 and 3, but not entirely ruling out 1.
I just committed some code like "if e.errno == errno.EWIN". I had not realized not all constants are defined on all systems, although it is documented so I have no excuse. The problem you report:
Would be solved if both OSWinError and OSLinError were always defined in both Linux and Windows Python. Programs could be written to catch both OSWinError and OSLinError, except that on Linux OSWinError would never actually be raised, and on Windows OSLinError would never occur. Problem solved. The downsides of this? I can only see memory, at the moment, but I might be missing something. Now just one final word why I think this matters. The currently correct way to remove a directory tree and only ignore the error "it does not exist" is: try: shutil.rmtree("dirname") except OSError, e: if errno.errorcode[e.errno] != 'ENOENT': raise However, only very experienced programmers will know to write that correct code (apparently I am not experienced enought!). What I am proposing is that the simpler correct code would be something like: try: shutil.rmtree("dirname") except OSNoEntryError: pass Much simpler, no? Right now, developers are tempted to write code like: shutil.rmtree("dirname", ignore_errors=True) Or: try: shutil.rmtree("dirname") except OSError: pass Both of which follow the error hiding anti-pattern [1]. [1] http://en.wikipedia.org/wiki/Error_hiding Thanks for reading this far. -- Gustavo J. A. M. Carneiro INESC Porto, Telecommunications and Multimedia Unit "The universe is always one step beyond logic." -- Frank Herbert

On Thu, Apr 2, 2009 at 1:10 PM, Gustavo Carneiro <gjcarneiro@gmail.com> > Sorry. I suck at this. I think I'm too impatient (read: time constrained)
to be polite :P
OK, ditto. :)
Yeah, but now you'd have to generate the list of exceptions (which would be enormously long) based on the union of all errno codes in the universe. Unless you only want to do it for some errno codes and not for others, which sounds like asking for trouble. Also you need a naming scheme that works for all errnos and doesn't require manual work. Frankly, the only scheme that I can think of that could be automated would be something like OSError_ENAME. And, while OSError is built-in, I think these exceptions (because there are so many) should not be built-in, and probably not even live in the 'os' namespace -- the best place for them would be the errno module, so errno.OSError_ENAME.
The downsides of this? I can only see memory, at the moment, but I might be missing something.
It's an enormous amount of work to make it happen across all platforms. And it doesn't really solve an important problem.
That doesn't strike me as correct at all, since it doesn't distinguish between ENOENT being raised for some file deep down in the tree vs. the root not existing. (This could happen if after you did os.listdir() some other process deleted some file.) A better way might be try: shutil.rmtree(<dir>) except OSError: if os.path.exists(<dir>): raise Though I don't know what you wish to happen of <dir> were a dangling symlink.
And wrong.
Thanks for not wasting any more of my time. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

(cross-posting back to python-dev to finalize discussions) 2009/4/2 Guido van Rossum <guido@python.org> [...]
I partially agree. It will be a lot of work. I think the problem is valid, although not very important, I agree.
OK. Maybe in a generic case this could happen, although I'm sure this won't happen in my particular scenario. This is about a build system, and I am assuming there are no two concurrent builds (or else a lot of other things would fail anyway).
Sure, this works, but at the cost of an extra system call. I think it's more elegant to check the errno (assuming the corner case you pointed out above is not an issue).
OK, I won't waste more time. If this were an obvious improvement beyond doubt to most people, I would pursue it, but since it's not, I can live with it. Thanks anyway, -- Gustavo J. A. M. Carneiro INESC Porto, Telecommunications and Multimedia Unit "The universe is always one step beyond logic." -- Frank Herbert

Guido van Rossum wrote:
Also, some platforms may have a rather large number of possible error codes. Not sure what MacOSX is like, but Classic MacOS had literally *hundreds* of OSError values. Having a class for each one would be rather unwieldy. What might make more sense is to have a way of attaching a guard expression to an except clause, maybe except OSError as e if e.errno = ESPAM: ... -- Greg

2009/4/2 Guido van Rossum <guido@python.org>
Sorry. I suck at this. I think I'm too impatient (read: time constrained) to be polite :P
Maybe I didn't express myself very well. By "no will to do it" I meant "no interest to do it". If you thought it was a bad idea you would have no interest in doing it. To be frank, what I thought most likely was that, with all the refactoring going on in Python 3, this issue, which was an obvious cleanup to me (but now I realize it is not obvious at all to everyone else), was overlooked because there were bigger problems to solve. So there are usually only three reasons why something is not done: 1- It's a bad idea; 2- No one thought of it; 3- It's a good and known idea, but there was no manpower to do it. I was betting more on 2 and 3, but not entirely ruling out 1.
I just committed some code like "if e.errno == errno.EWIN". I had not realized not all constants are defined on all systems, although it is documented so I have no excuse. The problem you report:
Would be solved if both OSWinError and OSLinError were always defined in both Linux and Windows Python. Programs could be written to catch both OSWinError and OSLinError, except that on Linux OSWinError would never actually be raised, and on Windows OSLinError would never occur. Problem solved. The downsides of this? I can only see memory, at the moment, but I might be missing something. Now just one final word why I think this matters. The currently correct way to remove a directory tree and only ignore the error "it does not exist" is: try: shutil.rmtree("dirname") except OSError, e: if errno.errorcode[e.errno] != 'ENOENT': raise However, only very experienced programmers will know to write that correct code (apparently I am not experienced enought!). What I am proposing is that the simpler correct code would be something like: try: shutil.rmtree("dirname") except OSNoEntryError: pass Much simpler, no? Right now, developers are tempted to write code like: shutil.rmtree("dirname", ignore_errors=True) Or: try: shutil.rmtree("dirname") except OSError: pass Both of which follow the error hiding anti-pattern [1]. [1] http://en.wikipedia.org/wiki/Error_hiding Thanks for reading this far. -- Gustavo J. A. M. Carneiro INESC Porto, Telecommunications and Multimedia Unit "The universe is always one step beyond logic." -- Frank Herbert

On Thu, Apr 2, 2009 at 1:10 PM, Gustavo Carneiro <gjcarneiro@gmail.com> > Sorry. I suck at this. I think I'm too impatient (read: time constrained)
to be polite :P
OK, ditto. :)
Yeah, but now you'd have to generate the list of exceptions (which would be enormously long) based on the union of all errno codes in the universe. Unless you only want to do it for some errno codes and not for others, which sounds like asking for trouble. Also you need a naming scheme that works for all errnos and doesn't require manual work. Frankly, the only scheme that I can think of that could be automated would be something like OSError_ENAME. And, while OSError is built-in, I think these exceptions (because there are so many) should not be built-in, and probably not even live in the 'os' namespace -- the best place for them would be the errno module, so errno.OSError_ENAME.
The downsides of this? I can only see memory, at the moment, but I might be missing something.
It's an enormous amount of work to make it happen across all platforms. And it doesn't really solve an important problem.
That doesn't strike me as correct at all, since it doesn't distinguish between ENOENT being raised for some file deep down in the tree vs. the root not existing. (This could happen if after you did os.listdir() some other process deleted some file.) A better way might be try: shutil.rmtree(<dir>) except OSError: if os.path.exists(<dir>): raise Though I don't know what you wish to happen of <dir> were a dangling symlink.
And wrong.
Thanks for not wasting any more of my time. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

(cross-posting back to python-dev to finalize discussions) 2009/4/2 Guido van Rossum <guido@python.org> [...]
I partially agree. It will be a lot of work. I think the problem is valid, although not very important, I agree.
OK. Maybe in a generic case this could happen, although I'm sure this won't happen in my particular scenario. This is about a build system, and I am assuming there are no two concurrent builds (or else a lot of other things would fail anyway).
Sure, this works, but at the cost of an extra system call. I think it's more elegant to check the errno (assuming the corner case you pointed out above is not an issue).
OK, I won't waste more time. If this were an obvious improvement beyond doubt to most people, I would pursue it, but since it's not, I can live with it. Thanks anyway, -- Gustavo J. A. M. Carneiro INESC Porto, Telecommunications and Multimedia Unit "The universe is always one step beyond logic." -- Frank Herbert

Guido van Rossum wrote:
Also, some platforms may have a rather large number of possible error codes. Not sure what MacOSX is like, but Classic MacOS had literally *hundreds* of OSError values. Having a class for each one would be rather unwieldy. What might make more sense is to have a way of attaching a guard expression to an except clause, maybe except OSError as e if e.errno = ESPAM: ... -- Greg
participants (3)
-
Greg Ewing
-
Guido van Rossum
-
Gustavo Carneiro