Issue15767
Created on 2012-08-22 19:45 by eric.snow, last changed 2013-02-20 03:50 by eric.snow.
| Messages (31) | |||
|---|---|---|---|
| msg168906 - (view) | Author: Eric Snow (eric.snow) * ![]() |
Date: 2012-08-22 19:45 | |
In issue 15316 (msg168896, Brett Cannon): Create a ModuleNotFoundError exception that subclasses ImportError and catch that (breaks doctests and introduces a new exception that people will need to be aware of, plus the question of whether it should just exist in importlib or be a builtin) While it's too late to go into 3.3, this is a reasonable addition for 3.4. Perhaps other ImportError subclasses are warranted, but they can be addressed separately. |
|||
| msg175638 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2012-11-15 20:40 | |
Should it be ModuleNotFoundError or ModuleNotFound? It's not necessarily an error if a module doesn't exist, so failing to find it isn't quite that negative. It also acts somewhat like StopIteration/GeneratorExit which also don't have the common "Error" suffix of exception names. |
|||
| msg175650 - (view) | Author: Chris Jerdonek (chris.jerdonek) * ![]() |
Date: 2012-11-15 22:02 | |
Since it subclasses ImportError, it seems like we're already considering it to be an error? StopIteration and GeneratorExit don't inherit from an "Error" exception type unlike, say, the OSError exception types. |
|||
| msg175651 - (view) | Author: Chris Jerdonek (chris.jerdonek) * ![]() |
Date: 2012-11-15 22:03 | |
I meant to include this link for convenience: http://docs.python.org/dev/library/exceptions.html#exception-hierarchy |
|||
| msg175659 - (view) | Author: Eric Snow (eric.snow) * ![]() |
Date: 2012-11-16 00:03 | |
I'd say ModuleNotFoundError. You could argue that other exception types aren't really errors in certain circumstances. I'd think that generally this would be an error. |
|||
| msg175660 - (view) | Author: Eric Snow (eric.snow) * ![]() |
Date: 2012-11-16 00:03 | |
Effectively the exception indicates that the import system had an error. |
|||
| msg175674 - (view) | Author: Ezio Melotti (ezio.melotti) * ![]() |
Date: 2012-11-16 10:13 | |
I prefer ModuleNotFound. Its meaning is already clear enough, even without the Error suffix. OTOH we now have FileNotFoundError, but all the other OSError subclasses have that suffix. In general I think the suffix is necessary when it's not already clear from the name that we are dealing with an exception, otherwise it can be dropped. |
|||
| msg175699 - (view) | Author: Chris Jerdonek (chris.jerdonek) * ![]() |
Date: 2012-11-16 18:21 | |
To state more explicitly the observation I alluded to in my comment above, we currently follow (without exception -- pun intended :) ) the convention that subclasses of exceptions that end in "Error" also end in "Error". We also do the same with the suffix "Warning". The latter is another reason to include the suffix "Error" -- to eliminate ambiguity as to whether the exception type inherits from a Warning class (e.g. from ImportWarning). |
|||
| msg175703 - (view) | Author: Ezio Melotti (ezio.melotti) * ![]() |
Date: 2012-11-16 18:53 | |
That seems indeed to be the case with built-in exceptions. I'm not sure if it's intentional or just a coincidence. I agree that warnings should always have a "Warning" suffix to distinguish them from exceptions, but in the stdlib the "Error" suffix is not used consistently. There are exceptions like: FloatOperation, DivisionByZero, InvalidOperation, TimeoutExpired, BrokenProcessPool, BufferTooShort, ImproperConnectionState, UnknownProtocol, InvalidURL, etc.. Anyway I don't have a strong opinion about this, so if you think the name should be ModuleNotFoundError it's OK with me (i.e. I'm -0). |
|||
| msg181901 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2013-02-11 15:40 | |
For me, it mostly comes down to whether end-users are expected to see such errors generally or not. We see ImportErrors all the time, and they are clearly errors. If we're expected to see and deal with MNF, and if in such cases it's generally considered an error, then MNFError is better. If it's mostly an internal/hidden thing, then MNF doesn't bother me. |
|||
| msg181914 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-11 17:31 | |
Right, so what's typical? =) I mean do most people see ImportError for optional modules (e.g. not on support platforms), or do most people see ImportError because they messed up and tried to import something that they expected but actually isn't there for some reason. |
|||
| msg181919 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2013-02-11 18:33 | |
On Feb 11, 2013, at 05:31 PM, Brett Cannon wrote: >Right, so what's typical? =) I mean do most people see ImportError for >optional modules (e.g. not on support platforms), or do most people see >ImportError because they messed up and tried to import something that they >expected but actually isn't there for some reason. There are a few common use cases (or perhaps anti-use cases) where you see ImportErrors. I might be missing some, but I'd put these in roughly descending order of commonness. * Trying alternative imports for compatibility reasons. You always expect ImportErrors in these cases, and you'll always catch them in try/excepts. * Missing modules, submodules, or attributes in from-imports. These can be unexpected if you think you've got the right version of a package, or expected for compatibility reasons. * Trying to conditionally import optional modules. Again, expected, and they'll be wrapped in try/except. I guess the case you're trying to differentiate with MNF is, the from-import case, i.e. did the error occur because the module was missing or because the attribute was missing? It's hard to say which is more likely, which I guess is why you're having a hard time deciding. :) If I had to vote, I'd go with MNFError 1) because it's a subclass of ImportError; 2) it'll be more informative in the case where it really *is* an error; 3) isn't that big of a deal in cases where it's expected; 4) we're used to seeing ImportError anyway, and probably most code won't care and will just use ImportError. |
|||
| msg181926 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-11 19:18 | |
Screw it, I'll go with ModuleNotFoundError since it is a subclass of ImportError and so it might come off as weird as saying the superclass is an "Error" but the subclass is not. |
|||
| msg182260 - (view) | Author: Eric Snow (eric.snow) * ![]() |
Date: 2013-02-17 04:18 | |
+1 on just getting it done with ModuleNotFoundError. FWIW, I'd be glad to do it. I'm taking a self-imposed break from the nearly finished C-OrderedDict! |
|||
| msg182263 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * ![]() |
Date: 2013-02-17 09:44 | |
from foo import bar Here bar can be not module, but an attribute of foo (for example, os.path). What error will be raised in this case? Module or attribute - this is an implementation detail; why do we distinguish between these cases? |
|||
| msg182271 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-17 14:43 | |
Eric: knock yourself out. =) Serhiy: What exception is raised in that situation is controlled by the eval loop, not importlib so that would be a separate change. But regardless, there is no way to infer whether you expected an attribute or module to be there, just that you were after something that didn't exist. But I would argue most people import at the module level and not the attribute level, and so raising an ModuleNotFoundError would be acceptable. |
|||
| msg182322 - (view) | Author: Antoine Pitrou (pitrou) * ![]() |
Date: 2013-02-18 13:48 | |
I've lost track of why this new exception was needed. Could someone provide a summary? Thanks :-) |
|||
| msg182332 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-18 18:36 | |
TL;DR for Antoine: when using a fromlist, import failures from that list are silently ignored. Because ImportError is overloaded in terms of what it means (e.g. bag magic number, module not found) there needs to be a clean way to tell the import failed because the module wasn't found so other ImportError reasons can properly propagate. |
|||
| msg182339 - (view) | Author: Chris Jerdonek (chris.jerdonek) * ![]() |
Date: 2013-02-18 20:10 | |
>> from foo import bar >> Here bar can be not module, but an attribute of foo (for example, os.path). > Serhiy: What exception is raised in that situation is controlled by the eval loop, not importlib so that would be a separate change. Just to clarify from this exchange, is there a chance we will use this same exception type (perhaps in a later change) in cases where bar is not found? If so, I think it's worth considering something like "NotFoundImportError" or "ImportNotFoundError" that doesn't single out module. Importing classes, etc. is quite a common pattern (e.g. examples appear in PEP 8). |
|||
| msg182385 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-19 14:52 | |
The original need was for internal importlib usage, but upon reflection it could also be used by the eval loop for that (http://hg.python.org/cpython/file/83d70dd58fef/Python/ceval.c#l4560), so I'm fine with changing the name to ImportNotFoundError. |
|||
| msg182396 - (view) | Author: Antoine Pitrou (pitrou) * ![]() |
Date: 2013-02-19 17:02 | |
> The original need was for internal importlib usage, but upon > reflection it could also be used by the eval loop for that > (http://hg.python.org/cpython/file/83d70dd58fef/Python/ceval.c#l4560), > so I'm fine with changing the name to ImportNotFoundError. I don't understand what ImportNotFoundError means: an import was not found? ModuleNotFoundError was obvious. |
|||
| msg182401 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-19 17:33 | |
Technically it should be ModuleOrSomeObjectNotFoundBecauseFromListIsTheBaneOfMyExistenceError, but we might be starting to mix paints for paints a shed shortly. Fine, that's 1 to 1 for ModuleNotFoundError vs. ImportNotFoundError. |
|||
| msg182404 - (view) | Author: Chris Jerdonek (chris.jerdonek) * ![]() |
Date: 2013-02-19 18:28 | |
If we can promise not to use it in the from-import case :) I'm okay with the more specific name (in fact it is preferable). From Brett's response, it sounds like we have flexibility there and don't need it to be the same? For from-import I would prefer the generic ImportError or adding a new type between ImportError and ModuleNotFoundError (like ImportNotFoundError) over using a name that is not entirely correct. |
|||
| msg182409 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * ![]() |
Date: 2013-02-19 19:24 | |
Can this be the same ImportError but with special flag? |
|||
| msg182411 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2013-02-19 19:44 | |
On Feb 19, 2013, at 07:24 PM, Serhiy Storchaka wrote: >Can this be the same ImportError but with special flag? Like an attribute on the exception? +1 |
|||
| msg182414 - (view) | Author: Antoine Pitrou (pitrou) * ![]() |
Date: 2013-02-19 19:49 | |
> >Can this be the same ImportError but with special flag? > > Like an attribute on the exception? +1 ImportError.has_different_meaning_but_too_lazy_to_create_a_distinct_exception_class_for_it ? (or perhaps you would prefer the camelCase version :-)) |
|||
| msg182415 - (view) | Author: Brett Cannon (brett.cannon) * ![]() |
Date: 2013-02-19 19:49 | |
Chris: Having a more generic name for import-from at the eval loop level on top of NoModuleFoundError is breaking the "practicality over purity" rule. ImportSearchFailed might be the closest we can come to a generic name for what occurred. Serihy & Barry: no. We do that now and it's already a nasty little hack. It would be better to let people catch an exception signaling that an import didn't happen because some module is missing than require introspection on a caught ImportError to tell what is going on (there's a reason why Antoine went to all of that trouble to add new exceptions so we don't have to look at the errno attribute on OSError). Exceptions are structured to work off of inheritance hierarchies (says the man who co-wrote the PEP to make all PEPs inherit from BaseException). |
|||
| msg182437 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2013-02-19 21:56 | |
On Feb 19, 2013, at 07:49 PM, Brett Cannon wrote: >Serihy & Barry: no. We do that now and it's already a nasty little hack. It >would be better to let people catch an exception signaling that an import >didn't happen because some module is missing than require introspection on a >caught ImportError to tell what is going on (there's a reason why Antoine >went to all of that trouble to add new exceptions so we don't have to look at >the errno attribute on OSError). Exceptions are structured to work off of >inheritance hierarchies (says the man who co-wrote the PEP to make all PEPs >inherit from BaseException). The difference being that checking errno on OSError/IOError is essentially required to do anything useful with it, while this one seems like a rare corner case (we've been doing pretty well without it so far). |
|||
| msg182455 - (view) | Author: Eric Snow (eric.snow) * ![]() |
Date: 2013-02-20 00:25 | |
The common case for catching ImportError is exactly what ModuleNotFoundError represents. If people are already going to change their code to handle just this special case, I'd think having the subclass would be the better route. I find it simpler (both to update existing code and to read:
try:
from _thread import _local as local
except ModuleNotFoundError:
from _threading_local import local
vs.
try:
from _thread import _local as local
except ImportError as e:
if e.not_found:
from _threading_local import local
else:
raise
And for the broader case:
try:
import breakfast
except ModuleNotFoundError:
class breakfast:
spam = 0
eggs = 1
ham = 2
except ImportError as e:
log_some_message("uh oh: {}".format(e))
raise
vs.
try:
import breakfast
except ImportError as e:
if e.not_found:
class breakfast:
spam = 0
eggs = 1
ham = 2
else:
log_some_message("uh oh: {}".format(e))
raise
|
|||
| msg182459 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * ![]() |
Date: 2013-02-20 01:02 | |
Why not just
try:
from _thread import _local as local
except ImportError:
from _threading_local import local
?
|
|||
| msg182466 - (view) | Author: Eric Snow (eric.snow) * ![]() |
Date: 2013-02-20 03:50 | |
Right. Sorry I wasn't more clear. Existing code will continue to work either way. The point is in exposing the distinct module/name-not-found case, which I consider to be the common case for catching ImportError. My examples cover the case where you want to handle the module-not-found case specifically. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2013-02-20 03:50:35 | eric.snow | set | messages: + msg182466 |
| 2013-02-20 01:02:13 | serhiy.storchaka | set | messages: + msg182459 |
| 2013-02-20 00:25:08 | eric.snow | set | messages: + msg182455 |
| 2013-02-19 21:56:19 | barry | set | messages: + msg182437 |
| 2013-02-19 19:49:38 | brett.cannon | set | messages: + msg182415 |
| 2013-02-19 19:49:23 | pitrou | set | messages: + msg182414 |
| 2013-02-19 19:44:30 | barry | set | messages: + msg182411 |
| 2013-02-19 19:24:21 | serhiy.storchaka | set | messages: + msg182409 |
| 2013-02-19 18:28:16 | chris.jerdonek | set | messages: + msg182404 |
| 2013-02-19 17:33:31 | brett.cannon | set | messages: + msg182401 |
| 2013-02-19 17:02:43 | pitrou | set | messages: + msg182396 |
| 2013-02-19 14:52:13 | brett.cannon | set | messages:
+ msg182385 title: add ModuleNotFoundError -> add ImportNotFoundError |
| 2013-02-18 20:10:46 | chris.jerdonek | set | messages: + msg182339 |
| 2013-02-18 18:36:53 | brett.cannon | set | messages: + msg182332 |
| 2013-02-18 16:57:12 | maker | set | nosy:
- maker |
| 2013-02-18 13:48:06 | pitrou | set | nosy:
+ pitrou messages: + msg182322 |
| 2013-02-17 21:01:15 | Arfrever | set | nosy:
+ Arfrever |
| 2013-02-17 14:43:55 | brett.cannon | set | messages: + msg182271 |
| 2013-02-17 09:44:32 | serhiy.storchaka | set | nosy:
+ serhiy.storchaka messages: + msg182263 |
| 2013-02-17 04:18:03 | eric.snow | set | messages: + msg182260 |
| 2013-02-11 19:18:32 | brett.cannon | set | messages: + msg181926 |
| 2013-02-11 18:33:40 | barry | set | messages: + msg181919 |
| 2013-02-11 17:31:00 | brett.cannon | set | messages: + msg181914 |
| 2013-02-11 15:40:40 | barry | set | messages: + msg181901 |
| 2013-02-11 15:37:52 | barry | set | nosy:
+ barry |
| 2012-11-16 18:53:46 | ezio.melotti | set | messages: + msg175703 |
| 2012-11-16 18:21:15 | chris.jerdonek | set | messages: + msg175699 |
| 2012-11-16 10:13:58 | ezio.melotti | set | messages: + msg175674 |
| 2012-11-16 00:03:56 | eric.snow | set | messages: + msg175660 |
| 2012-11-16 00:03:29 | eric.snow | set | messages: + msg175659 |
| 2012-11-15 22:03:24 | chris.jerdonek | set | messages: + msg175651 |
| 2012-11-15 22:02:29 | chris.jerdonek | set | messages: + msg175650 |
| 2012-11-15 20:40:47 | brett.cannon | set | stage: needs patch -> test needed |
| 2012-11-15 20:40:27 | brett.cannon | set | messages: + msg175638 |
| 2012-11-01 22:08:19 | asvetlov | set | nosy:
+ asvetlov |
| 2012-10-06 10:27:41 | maker | set | nosy:
+ maker |
| 2012-08-27 07:34:41 | cvrebert | set | nosy:
+ cvrebert |
| 2012-08-26 05:54:10 | ezio.melotti | set | nosy:
+ ezio.melotti |
| 2012-08-22 20:14:50 | chris.jerdonek | set | nosy:
+ chris.jerdonek |
| 2012-08-22 19:45:17 | eric.snow | create | |
