| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,6 +13,7 @@ | |||
| 13 | 13 | import tempfile | |
| 14 | 14 | import random | |
| 15 | 15 | import string | |
| 16 | + import importlib.machinery | ||
| 16 | 17 | from test import support | |
| 17 | 18 | import shutil | |
| 18 | 19 | from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, | |
@@ -5194,6 +5195,16 @@ def test_windows_only_module_error(self): | |||
| 5194 | 5195 | else: | |
| 5195 | 5196 | self.fail("ModuleNotFoundError was not raised") | |
| 5196 | 5197 | ||
| 5198 | + def test_find_incompatible_extension_modules(self): | ||
| 5199 | + """_find_incompatible_extension_modules assumes the last extension in | ||
| 5200 | + importlib.machinery.EXTENSION_SUFFIXES (defined in Python/dynload_*.c) | ||
| 5201 | + is untagged (eg. .so, .pyd). | ||
| 5202 | + | ||
| 5203 | + This test exists to make sure that assumption is correct. | ||
| 5204 | + """ | ||
| 5205 | + if importlib.machinery.EXTENSION_SUFFIXES: | ||
| 5206 | + self.assertEqual(len(importlib.machinery.EXTENSION_SUFFIXES[-1].split('.')), 2) | ||
| 5207 | + | ||
| 5197 | 5208 | ||
| 5198 | 5209 | class TestColorizedTraceback(unittest.TestCase): | |
| 5199 | 5210 | maxDiff = None | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1129,6 +1129,11 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, | |||
| 1129 | 1129 | self._str += (". Site initialization is disabled, did you forget to " | |
| 1130 | 1130 | + "add the site-packages directory to sys.path " | |
| 1131 | 1131 | + "or to enable your virtual environment?") | |
| 1132 | + elif abi_tag := _find_incompatible_extension_module(module_name): | ||
| 1133 | + self._str += ( | ||
| 1134 | + ". Although a module with this name was found for a " | ||
| 1135 | + f"different Python version ({abi_tag})." | ||
| 1136 | + ) | ||
| 1132 | 1137 | else: | |
| 1133 | 1138 | suggestion = _compute_suggestion_error(exc_value, exc_traceback, module_name) | |
| 1134 | 1139 | if suggestion: | |
@@ -1880,3 +1885,21 @@ def _levenshtein_distance(a, b, max_cost): | |||
| 1880 | 1885 | # Everything in this row is too big, so bail early. | |
| 1881 | 1886 | return max_cost + 1 | |
| 1882 | 1887 | return result | |
| 1888 | + | ||
| 1889 | + | ||
| 1890 | + def _find_incompatible_extension_module(module_name): | ||
| 1891 | + import importlib.machinery | ||
| 1892 | + import importlib.resources | ||
| 1893 | + | ||
| 1894 | + if not module_name or not importlib.machinery.EXTENSION_SUFFIXES: | ||
| 1895 | + return | ||
| 1896 | + | ||
| 1897 | + # We assume the last extension is untagged (eg. .so, .pyd)! | ||
| 1898 | + # tests.test_traceback.MiscTest.test_find_incompatible_extension_modules | ||
| 1899 | + # tests that assumption. | ||
| 1900 | + untagged_suffix = importlib.machinery.EXTENSION_SUFFIXES[-1] | ||
| 1901 | + | ||
| 1902 | + parent, _, child = module_name.rpartition('.') | ||
| 1903 | + for entry in importlib.resources.files(parent).iterdir(): | ||
| 1904 | + if entry.name.startswith(child + '.') and entry.name.endswith(untagged_suffix): | ||
| 1905 | + return entry.name.removeprefix(child + '.').removesuffix(untagged_suffix) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Add :exc:`ModuleNotFoundError` hints when a module for a different ABI | ||
| 2 | + exists. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments