|
10 | 10 | import keyword |
11 | 11 | import tokenize |
12 | 12 | import io |
| 13 | +import importlib.util |
13 | 14 | import _colorize |
14 | 15 |
|
15 | 16 | from contextlib import suppress |
@@ -1124,6 +1125,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, |
1124 | 1125 | self._str += (". Site initialization is disabled, did you forget to " |
1125 | 1126 | + "add the site-packages directory to sys.path " |
1126 | 1127 | + "or to enable your virtual environment?") |
| 1128 | + else: |
| 1129 | + suggestion = _compute_suggestion_error(exc_value, exc_traceback, module_name) |
| 1130 | + if suggestion: |
| 1131 | + self._str += f". Did you mean: '{suggestion}'?" |
1127 | 1132 | elif exc_type and issubclass(exc_type, (NameError, AttributeError)) and \ |
1128 | 1133 | getattr(exc_value, "name", None) is not None: |
1129 | 1134 | wrong_name = getattr(exc_value, "name", None) |
@@ -1672,6 +1677,18 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): |
1672 | 1677 | d = [x for x in d if x[:1] != '_'] |
1673 | 1678 | except Exception: |
1674 | 1679 | return None |
| 1680 | + elif isinstance(exc_value, ModuleNotFoundError): |
| 1681 | + try: |
| 1682 | + if parent_name := wrong_name.rpartition('.')[0]: |
| 1683 | + parent = importlib.util.find_spec(parent_name) |
| 1684 | + else: |
| 1685 | + parent = None |
| 1686 | + d = [] |
| 1687 | + for finder in sys.meta_path: |
| 1688 | + if discover := getattr(finder, 'discover', None): |
| 1689 | + d += [spec.name for spec in discover(parent)] |
| 1690 | + except Exception: |
| 1691 | + return None |
1675 | 1692 | elif isinstance(exc_value, ImportError): |
1676 | 1693 | try: |
1677 | 1694 | mod = __import__(exc_value.name) |
|
0 commit comments