[Python-Dev] PEP 3151 from the BDFOP (original) (raw)

Antoine Pitrou solipsis at pitrou.net
Mon Aug 29 23:39:33 CEST 2011


On Mon, 29 Aug 2011 17🔞33 -0400 Barry Warsaw <barry at python.org> wrote:

On Aug 24, 2011, at 01:57 AM, Antoine Pitrou wrote:

>> One guiding principle for me is that we should keep the abstraction as thin >> as possible. In particular, I'm concerned about mapping multiple errnos >> into a single Error. For example both EPIPE and ESHUTDOWN mapping to >> BrokePipeError, or EACESS or EPERM to PermissionError. I think we should >> resist this, so that one errno maps to exactly one Error. Where grouping >> is desired, Python already has mechanisms to deal with that, >> e.g. superclasses and multiple inheritance. Therefore, I think it would be >> better to have >> >> + FileSystemPermissionError >> + AccessError (EACCES) >> + PermissionError (EPERM) > >I'm not sure that's a good idea: Was it the specific grouping under FileSystemPermissionError that you're objecting to, or the "keep the abstraction thin" principle?

The former. EPERM is generally returned for things which aren't filesystem-related. (although I also think separating EACCES and EPERM is of little value in practice)

Let's say we threw out the idea of FSPE superclass, would you still want to collapse EACCES and EPERM into PermissionError, or would separate exceptions for each be okay?

I have a preference for the former, but am not against the latter. I just think that, given AccessError and PermissionError, most users won't know up front which one they should care about.

It's still pretty easy to catch both in one except clause, and it won't be too annoying if it's rare.

Indeed.

Reading your IRC message (sorry, I was afk) it sounds like you think FileSystemError can be removed. I like keeping the hierarchy flat.

Ok. It can be reintroduced later on. (the main reason why I think it can be removed is that EACCES in itself is often tied to filesystem access rights; so the EACCES exception class would have to be a subclass of FileSystemError, while the EPERM one should not :-))

>>>> open("foo") >Traceback (most recent call last): > File "", line 1, in >FileNotFoundError: [Errno 2] No such file or directory: 'foo' > >(see e.g. http://bugs.python.org/issue12762)

True, but since you're going to be creating a bunch of new exception classes, it should be relatively painless to give them a better str. Thanks for pointing out that bug; I agree with it.

Well, the str right now is exactly the same as OSError's.

My question mostly was about raising OSError (as the current PEP states) with an errno that does not map to one of the new exceptions. In that case, I don't think there's anything you could raise other than exactly OSError, right?

And indeed, that's what the implementation does :)

So, for raising OSError with an errno mapping to one of the subclasses, it appears to break the "explicit is better than implicit" principle, and I think it could lead to hard-to-debug or understand code. You'll look at code that raises OSError, but the exception that gets printed will be one of the subclasses. I'm afraid that if you don't know that this is happening, you're going to think you're going crazy.

Except that it only happens if you use a recognized errno. For example if you do:

>>> OSError(errno.ENOENT, "not found")
FileNotFoundError(2, 'not found')

Not if you just pass a message (or anything else, actually):

>>> OSError("some message")
OSError('some message',)

But if you pass an explicit errno, then the subclass doesn't appear that surprising, does it?

The other half is, let's say raising FileNotFoundError with the EEXIST errno. I'm guessing that the init's for the new OSError subclasses will not have an errno attribute, so there's no way you can do that, but the PEP does not discuss this.

Actually, the new and the init are exactly the same as OSError's:

e = FileNotFoundError("some message") e.errno e = FileNotFoundError(errno.ENOENT, "some message") e.errno 2

>Wow, I didn't know ESRCH. >How would you call the respective exceptions? >- ChildProcessError for ECHILD? [...]

>- ProcessLookupError for ESRCH? [...] So in a sense, both are lookup errors, though I think it's going too far to multiply inherit from LookupError. Maybe ChildWaitError or ChildLookupError for the former? ProcessLookupError seems good to me.

Ok.

>> What if all the errno symbolic names were mapped as attributes on IOError? >> The only advantage of that would be to eliminate the need to import errno, >> or for the ugly e.errno == errno.ENOENT stuff. That would then be >> rewritten as e.errno == IOError.ENOENT. A mild savings to be sure, but >> still. > >Hmm, I guess that's explorable as an orthogonal idea.

Cool. How should we capture that?

A separate PEP perhaps, or more appropriately (IMHO) a tracker entry, since it's just about enriching the attributes of an existing type. I think it's a bit weird to define a whole lot of constants on a built-in type, though.

Okay, so here's what's still outstanding for me:

* Should we eliminate FileSystemError? (probably "yes")

Ok.

* Should we ensure one errno == one exception? - i.e. separate EACCES and EPERM - i.e. separate EPIPE and ESHUTDOWN

I think that's unhelpful (or downright confusing: what is, intuitively, the difference between an "AccessError" and a "PermissionError"?) to most users, and users to which it is helpful already know how to access the errno.

* Should the str of the new exception subclasses be improved (e.g. to include the symbolic name instead of the errno first)?

As I said, I think it's orthogonal, but I would +1 on including the symbolic name instead of the integer.

* Is the OSError.new() hackery a good idea?

I think it is, since it also takes care about Python code raising OSErrors, but YMMV.

* Should the PEP define the signature of the new exceptions (e.g. to prohibit passing in an incorrect errno to an OSError subclass)?

The OSError constructor, pre-PEP, is very laxist, and I took care to keep it like that in the implementation. Apparently it's a feature to help migrating old code.

* Can we add ECHILD and ESRCH, and if so, what names should we use?

I think the suggested names are ok.

* Where can we capture the idea of putting the symbolic names on OSError class attributes, or is it a dumb idea that should be ditched?

I think it's a separate task altogether, although I'm in favour of it.

* How long should we wait for other Python implementations to chime in?

A couple of weeks? I will soon leave on holiday until the end of September anyway.

Regards

Antoine.



More information about the Python-Dev mailing list