You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add import suggestions for ModuleNotFoundError #134872
#134175 It is a suggest for the top module. But we can use it in this issue.
In the feature in this issue, the child module will raise like this.
>>>importmultprocessing.dummy.connection#wrong in top moduleTraceback(mostrecentcalllast):
File"<python-input-0>"line1, in<module>importmultprocessing.dummy.connection#wrong in top module^^^^^^^^^^^^^^ModuleNotFoundError: nomodulenamed'multprocessing'. Didyoumean'multiprocessing'?
>>>importmultiprocessing.dumy.connection#wrong in first child moduleTraceback(mostrecentcalllast):
File"<python-input-1>"line1, in<module>importmultiprocessing.dumy.connection#wrong in first child module~~~~~~~~~~~~~~~~^^^^ModuleNotFoundError: module'multiprocessing'hasnochildmodule'dumy'. Didyoumean'dummy'?
>>>importmultiprocessing.dummy.connections#wrong in second child moduleTraceback(mostrecentcalllast):
File"<python-input-2>"line1, in<module>importmultiprocessing.dummy.connections#wrong in second child module~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ModuleNotFoundError: module'multiprocessing.dummy'hasnochildmodule'connections'. Didyoumean'connection'?
The user can see clearly which module is wrong first in import.
I'm still not convinced by this. This would require discovering modules that are deeply nested. What if we have a.b.c and a.c.b and someone writes a.b.b. Should it be a.b.c or a.c.b? I'm going to close this one for now. Actually, my previous idea was wrong because the cache is built at the REPL level, but suggestions are raised at the interpreter's level so no we shouldn't only have suggestions in the REPL but no in the interpreter (that would make the treatment of exceptions way harder)
What if we have a.b.c and a.c.b and someone writes a.b.b. Should it be a.b.c or a.c.b
I don't know what it says. If it is a.b.b, the module 'a.b' will be successfully import first, so 'a.c.b' is impossible.
And anyway, there are two messages first:"no module named 'a.b.b'" and "module 'a.b' has no child module 'b'", which is more clear?
---- Replied Message ----
| From | Bénédikt ***@***.***> |
| Date | 08/09/2025 18:36 |
| To | ***@***.***> |
| Cc | ***@***.***>***@***.***> |
| Subject | Re: [python/cpython] Suggest for child module in ModuleNotFoundError (Issue #134872) |
picnixz left a comment (python/cpython#134872)
I'm still not convinced by this. This would require discovering modules that are deeply nested. What if we have a.b.c and a.c.b and someone writes a.b.b. Should it be a.b.c or a.c.b? I'm going to close this one for now. Actually, my previous idea was wrong because the cache is built at the REPL level, but suggestions are raised at the interpreter's level so no we shouldn't only have suggestions in the REPL but no in the interpreter (that would make the treatment of exceptions way harder)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you authored the thread.Message ID: ***@***.***>
So you would suggest that we only present children modules if any. Ok I misunderstood that part. However, the problem with the cache remains and changing this at the interpreter level (actually it would be in importlib/_bootstrap.py) would be too complex IMO (the cache may grow indefinitely and fast depending on the number of modules inside site-packages).
Before accepting such feature, I want first a PoC that doesn't affect import performance nor the runtime memory. Also, I don't think we should keep two issues open (though I closed both) for the same feature. If we can reuse the module completer from the REPL during bootstrapping (but I'm not sure we can rely on pkgutil because of that), maybe we could do something but I'm afraid it will be too complex.
Also, more generally, if we have two packages with close names, suggesting the correct one may be hard and still misleading (if we want to import say mod1 but we have mod2 and mod3, I don't really like suggesting mod2over mod3 or vice-versa; for delattr/getattr, it's usually fine because we don't have thousands of possible names, but for modules, collisions are more likely to happen IMO).
Also, more generally, if we have two packages with close names, suggesting the correct one may be hard and still misleading (if we want to import say mod1 but we have mod2 and mod3, I don't really like suggesting mod2over mod3 or vice-versa; for delattr/getattr, it's usually fine because we don't have thousands of possible names, but for modules, collisions are more likely to happen IMO).
I test the suggestion when there are many names in locals():
for i in range(1000000): exec(f"a{i}=1", globals())
a_1000
Then it doesn't suggest "did you mean 'a1000'?" So I think that if there are too many similar name it is nature that it won't suggest.
And I wrote a code to return all of the module name. However, I don't know whether the sys.builtin_module_names different, so it may be changed by #ifdef ...:
>>>a_1002=1
>>>a_1004=1
>>>a_1003
Traceback (most recent call last):
File "<python-input-6>", line 1, in <module>
a_1003
NameError: name 'a_1003' is not defined. Did you mean: 'a_1002'?
Yeah the maximum number of possible suggestions is 750 (harcoded in MAX_CANDIDATE_ITEMS) and we don't suggest for names longer than 40 characters.
As for iterating over the modules, we should be careful with whether the file is a module or not. pkgutil.iter_modules() iterates over the modules of a package but it still imports the packages. The problem we face however is that the cache needs to be built during import bootstrapping and maintained. However I'm not sure we can re-use import_module from importlib for that as it could then have a recursive issue (if we try to import a module that doesn't exist, and then try to check which are those that exist, then we may need to import a package, and for that we need to be able to use the import functions correctly).
Anyway, I would first suggest having a strong PoC that shows how to integrate this component in the bootstrapping. Checking for suggestions would be fine if we just export the functions that calculate the suggestions (we need them in C otherwise it'll be too slow I think).
And I wrote a code to return all of the module name. However, I don't know whether the sys.builtin_module_names different, so it may be changed by #ifdef ...:我写了一段代码来返回所有模块的名称。但是,我不知道 sys.builtin_module_names 是否不同,所以可以通过 #ifdef ... 来更改:
Now the question is :
Whether the function scan_dir() right in all of the system and hou to get the initialize the builtin_modules. Now I test it on windows and no problems.
As for iterating over the modules, we should be careful with whether the file is a module or not. pkgutil.iter_modules() iterates over the modules of a package but it still imports the packages. The problem we face however is that the cache needs to be built during import bootstrapping and maintained. However I'm not sure we can re-use import_module from importlib for that as it could then have a recursive issue (if we try to import a module that doesn't exist, and then try to check which are those that exist, then we may need to import a package, and for that we need to be able to use the import functions correctly).
Anyway, I would first suggest having a strong PoC that shows how to integrate this component in the bootstrapping. Checking for suggestions would be fine if we just export the functions that calculate the suggestions (we need them in C otherwise it'll be too slow I think).
Now it seems not a problem. See here. It is a better implement. The suggestions are given in traceback.py instead of the interpreter itself so that we can re-use the cache just in that file without any worries for recursive issue, though I didn't see any benifit for the cache used in here (In normal condition, I assumed that the maximun quantity of third-party libraries in one environment is 300, and the function scan_dir took 5ms to find the librarys in "site-packages").
Now the only problem is only the "__find__" method to help finding all of the modules from the custom import hook. It may be need a discussion.
Activity
picnixz commentedon Aug 9, 2025
I'm still not convinced by this. This would require discovering modules that are deeply nested. What if we have
a.b.canda.c.band someone writesa.b.b. Should it bea.b.cora.c.b? I'm going to close this one for now. Actually, my previous idea was wrong because the cache is built at the REPL level, but suggestions are raised at the interpreter's level so no we shouldn't only have suggestions in the REPL but no in the interpreter (that would make the treatment of exceptions way harder)Locked-chess-official commentedon Aug 9, 2025
picnixz commentedon Aug 9, 2025
So you would suggest that we only present children modules if any. Ok I misunderstood that part. However, the problem with the cache remains and changing this at the interpreter level (actually it would be in
importlib/_bootstrap.py) would be too complex IMO (the cache may grow indefinitely and fast depending on the number of modules insidesite-packages).Before accepting such feature, I want first a PoC that doesn't affect import performance nor the runtime memory. Also, I don't think we should keep two issues open (though I closed both) for the same feature. If we can reuse the module completer from the REPL during bootstrapping (but I'm not sure we can rely on pkgutil because of that), maybe we could do something but I'm afraid it will be too complex.
Also, more generally, if we have two packages with close names, suggesting the correct one may be hard and still misleading (if we want to import say
mod1but we havemod2andmod3, I don't really like suggestingmod2overmod3or vice-versa; for delattr/getattr, it's usually fine because we don't have thousands of possible names, but for modules, collisions are more likely to happen IMO).Locked-chess-official commentedon Aug 9, 2025
I test the suggestion when there are many names in
locals():Then it doesn't suggest "did you mean 'a1000'?" So I think that if there are too many similar name it is nature that it won't suggest.
Locked-chess-official commentedon Aug 9, 2025
And I wrote a code to return all of the module name. However, I don't know whether the
sys.builtin_module_namesdifferent, so it may be changed by#ifdef ...:Locked-chess-official commentedon Aug 9, 2025
For more test, the suggestion only get one name:
picnixz commentedon Aug 9, 2025
Yeah the maximum number of possible suggestions is 750 (harcoded in
MAX_CANDIDATE_ITEMS) and we don't suggest for names longer than 40 characters.As for iterating over the modules, we should be careful with whether the file is a module or not.
pkgutil.iter_modules()iterates over the modules of a package but it still imports the packages. The problem we face however is that the cache needs to be built during import bootstrapping and maintained. However I'm not sure we can re-useimport_modulefromimportlibfor that as it could then have a recursive issue (if we try to import a module that doesn't exist, and then try to check which are those that exist, then we may need to import a package, and for that we need to be able to use the import functions correctly).Anyway, I would first suggest having a strong PoC that shows how to integrate this component in the bootstrapping. Checking for suggestions would be fine if we just export the functions that calculate the suggestions (we need them in C otherwise it'll be too slow I think).
Locked-chess-official commentedon Aug 9, 2025
Now the question is :
Whether the function
scan_dir()right in all of the system and hou to get the initialize thebuiltin_modules. Now I test it on windows and no problems.Locked-chess-official commentedon Sep 9, 2025
Now it seems not a problem. See here. It is a better implement. The suggestions are given in
traceback.pyinstead of the interpreter itself so that we can re-use the cache just in that file without any worries for recursive issue, though I didn't see any benifit for the cache used in here (In normal condition, I assumed that the maximun quantity of third-party libraries in one environment is 300, and the functionscan_dirtook 5ms to find the librarys in "site-packages").Now the only problem is only the "__find__" method to help finding all of the modules from the custom import hook. It may be need a discussion.
Now the third-party library friendly_module_not_found_error is the monkey patch about it in all of the versions.
pythongh-134872: Add traceback suggestions for ModuleNotFoundError
pythongh-134872: Add traceback suggestions for ModuleNotFoundError
FFY00 commentedon Oct 10, 2025
I'm revisiting this with a new API proposal in GH-139899.
Here's a working implementation on top of GH-139900.
[-]Suggest for child module in ModuleNotFoundError[/-][+]Add `import` suggestions for `ModuleNotFoundError`[/+]MetaPathFinder.discoverandPathEntryFinder.discover#139899pythongh-134872: Add traceback suggestions for ModuleNotFoundError
pythongh-134872: Add traceback suggestions for ModuleNotFoundError
pythongh-134872: Add traceback suggestions for ModuleNotFoundError
pythongh-134872: Add traceback suggestions for ModuleNotFoundError
GH-134872: add ModuleNotFoundError suggestions (#142512)
FFY00 commentedon Feb 19, 2026
Implemented in GH-142512
pythonGH-134872: add ModuleNotFoundError suggestions (python#142512)
pythonGH-134872: add ModuleNotFoundError suggestions (python#142512)