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

Guido van Rossum guido at python.org
Thu Apr 2 22:37:47 CEST 2009


On Thu, Apr 2, 2009 at 1:10 PM, Gustavo Carneiro
<gjcarneiro at gmail.com> > Sorry.  I suck at this.  I think I'm too
impatient (read: time constrained)
> to be polite :P

OK, ditto. :)

>> 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..
>
> 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:
>>
>>  try:
>>    ...
>>  except OSWinError:
>>    ...
>>  except OSLinError:
>>    ...
>>
>
> 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.

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.

> 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!).

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.

> What I am proposing is that the simpler correct code would be something
> like:
>
> try:
>     shutil.rmtree("dirname")
> except OSNoEntryError:
>     pass
>
> Much simpler, no?

And wrong.

> 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.

Thanks for not wasting any more of my time.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-ideas mailing list