Skip to content

Commit 66586db

Browse files
Update traceback.py
1 parent c0f35c4 commit 66586db

File tree

1 file changed

+160
-9
lines changed

1 file changed

+160
-9
lines changed

Lib/traceback.py

Lines changed: 160 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,11 +1107,20 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
11071107
suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name)
11081108
if suggestion:
11091109
self._str += f". Did you mean: '{suggestion}'?"
1110-
elif exc_type and issubclass(exc_type, ModuleNotFoundError) and \
1111-
sys.flags.no_site and \
1112-
getattr(exc_value, "name", None) not in sys.stdlib_module_names:
1113-
self._str += (". Site initialization is disabled, did you forget to "
1114-
+ "add the site-packages directory to sys.path?")
1110+
elif exc_type and issubclass(exc_type, ModuleNotFoundError) and \
1111+
getattr(exc_value, "name", None):
1112+
wrong_name = getattr(exc_value, "name", None)
1113+
suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name)
1114+
self._str = exc_value.msg
1115+
if suggestion:
1116+
self._str += f". Did you mean: '{suggestion}'?"
1117+
if sys.flags.no_site and getattr(exc_value, "name", None) not in sys.stdlib_module_names:
1118+
if not suggestion:
1119+
self._str += (". Site initialization is disabled, did you forget to "
1120+
+ "add the site-packages directory to sys.path?")
1121+
else:
1122+
self._str += ("Or did you forget to add the site-packages directory to sys.path? The "
1123+
+ "site initialization is disabled")
11151124
elif exc_type and issubclass(exc_type, (NameError, AttributeError)) and \
11161125
getattr(exc_value, "name", None) is not None:
11171126
wrong_name = getattr(exc_value, "name", None)
@@ -1634,7 +1643,100 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
16341643
if wrong_name[:1] != '_':
16351644
d = [x for x in d if x[:1] != '_']
16361645
except Exception:
1637-
return None
1646+
scan_dir, find_all_packages = _find_all_packages()
1647+
import os
1648+
list_d = find_all_packages()
1649+
_module_name = exc_value.name
1650+
wrong_name_list = _module_name.split(".")
1651+
module_name = wrong_name_list[0]
1652+
if module_name not in sys.modules:
1653+
wrong_name = module_name
1654+
exc_value.msg = f"no module named '{module_name}'"
1655+
if len(wrong_name_list) == 1:
1656+
if (_closed_name := _calculate_closed_name(module_name, sorted(sys.stdlib_module_names))):
1657+
return _closed_name # stdlib first
1658+
_close_name_list = []
1659+
for i in list_d:
1660+
module_result = _calculate_closed_name(wrong_name, i)
1661+
if module_result:
1662+
_close_name_list.append(module_result)
1663+
_close_name_list.sorted()
1664+
return _closed_name_list[0]
1665+
else:
1666+
if wrong_name in sum(list_d, []):
1667+
path = ""
1668+
for i in sys.path:
1669+
if i and isinstance(i, str) and not i.endswith("idlelib"):
1670+
if wrong_name in scan_dir(i):
1671+
path = f"{i}/{wrong_name}"
1672+
break
1673+
else:
1674+
if (_closed_name := _calculate_closed_name(module_name, sorted(sys.stdlib_module_names))):
1675+
return _closed_name
1676+
_close_name_list = []
1677+
for i in list_d:
1678+
module_result = _calculate_closed_name(wrong_name, i)
1679+
if module_result:
1680+
_close_name_list.append(module_result)
1681+
_close_name_list.sorted()
1682+
return _closed_name_list[0]
1683+
else:
1684+
if (_closed_name := _calculate_closed_name(module_name, sorted(sys.stdlib_module_names))):
1685+
return _closed_name
1686+
_close_name_list = []
1687+
for i in list_d:
1688+
module_result = _calculate_closed_name(wrong_name, i)
1689+
if module_result:
1690+
_close_name_list.append(module_result)
1691+
_close_name_list.sorted()
1692+
return _closed_name_list[0]
1693+
1694+
if not os.path.exists(path) or not os.path.isdir(path):
1695+
exc_value.msg = f"module '{module_name}' has no child module '{wrong_name_list[1]}'; '{module_name}' is not a package"
1696+
return None
1697+
index = 0
1698+
for i in wrong_name_list[1:]:
1699+
index += 1
1700+
_child_modules_d = scan_dir(path)
1701+
original_module_name = module_name
1702+
if wrong_name_list[index] not in _child_modules_d:
1703+
exc_value.msg = f"module '{module_name}' has no child module '{i}'"
1704+
wrong_name = i
1705+
d = _child_modules_d
1706+
break
1707+
path += f"/{i}"
1708+
if not os.path.exists(path) or not os.path.isdir(path) and len(wrong_name_list) > index + 1:
1709+
module_name += "." + i
1710+
exc_value.msg = f"module '{module_name}' has no child module '{wrong_name_list[index + 1]}'; '{module_name}' is not a package"
1711+
return None
1712+
module_name += "." + i
1713+
exc_value.args = (exc_value.msg,)
1714+
else:
1715+
if hasattr(sys.modules[module_name], '__path__') and len(wrong_name_list)>1:
1716+
index = 0
1717+
for i in wrong_name_list[1:]:
1718+
index += 1
1719+
original_module_name = module_name
1720+
exc_value.msg = f"module '{module_name}' has no child module '{i}'"
1721+
exc_value.args = (exc_value.msg,)
1722+
module_name += "." + i
1723+
if module_name not in sys.modules:
1724+
wrong_name = i
1725+
d = scan_dir(sys.modules[original_module_name].__path__[0])
1726+
break
1727+
else:
1728+
if hasattr(sys.modules[module_name], '__path__'):
1729+
continue
1730+
else:
1731+
if len(wrong_name_list) > index + 1:
1732+
exc_value.msg = f"module '{module_name}' has no child module '{wrong_name_list[index+1]}'; '{module_name}' is not a package"
1733+
exc_value.args = (exc_value.msg,)
1734+
return None
1735+
else:
1736+
if len(wrong_name_list) > 1:
1737+
exc_value.msg = f"module '{module_name}' has no child module '{wrong_name_list[1]}'; '{module_name}' is not a package"
1738+
exc_value.args = (exc_value.msg,)
1739+
return None
16381740
else:
16391741
assert isinstance(exc_value, NameError)
16401742
# find most recent frame
@@ -1661,13 +1763,14 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
16611763
if has_wrong_name:
16621764
return f"self.{wrong_name}"
16631765

1766+
return _calculate_closed_name(wrong_name, d)
1767+
1768+
def _calculate_closed_name(wrong_name, d):
16641769
try:
16651770
import _suggestions
1771+
return _suggestions._generate_suggestions(d, wrong_name)
16661772
except ImportError:
16671773
pass
1668-
else:
1669-
return _suggestions._generate_suggestions(d, wrong_name)
1670-
16711774
# Compute closest match
16721775

16731776
if len(d) > _MAX_CANDIDATE_ITEMS:
@@ -1693,6 +1796,54 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
16931796
best_distance = current_distance
16941797
return suggestion
16951798

1799+
def _find_all_packages():
1800+
import os
1801+
import sys
1802+
from importlib import machinery
1803+
1804+
def scan_dir(path):
1805+
"""
1806+
Return all of the packages in the path without import
1807+
contains:
1808+
- .py file
1809+
- directory with "__init__.py"
1810+
- the .pyd/so file that has right ABI
1811+
"""
1812+
if not os.path.isdir(path):
1813+
return []
1814+
1815+
suffixes = machinery.EXTENSION_SUFFIXES
1816+
result = []
1817+
1818+
for name in os.listdir(path):
1819+
full_path = os.path.join(path, name)
1820+
1821+
# .py file
1822+
if name.endswith(".py") and os.path.isfile(full_path):
1823+
modname = name[:-3]
1824+
if modname.isidentifier():
1825+
result.append(modname)
1826+
1827+
# directory with "__init__.py"
1828+
elif os.path.isdir(full_path):
1829+
init_file = os.path.join(full_path, "__init__.py")
1830+
if os.path.isfile(init_file) and name.isidentifier():
1831+
result.append(name)
1832+
1833+
# the .pyd/so file that has right ABI
1834+
elif os.path.isfile(full_path):
1835+
for suf in suffixes:
1836+
if name.endswith(suf):
1837+
modname = name[:-len(suf)]
1838+
if modname.isidentifier():
1839+
result.append(modname)
1840+
break
1841+
1842+
return sorted(result)
1843+
1844+
def find_all_packages():
1845+
return [scan_dir(i) if i and isinstance(i, str) and not i.endswith("idlelib") else [] for i in sys.path] + [sorted(sys.builtin_module_names)]
1846+
return scan_dir, find_all_packages
16961847

16971848
def _levenshtein_distance(a, b, max_cost):
16981849
# A Python implementation of Python/suggestions.c:levenshtein_distance.

0 commit comments

Comments
 (0)