|
23 | 23 | import typing
|
24 | 24 | import typing_extensions
|
25 | 25 | import warnings
|
| 26 | +from collections import defaultdict |
26 | 27 | from contextlib import redirect_stderr, redirect_stdout
|
27 | 28 | from functools import singledispatch
|
28 | 29 | from pathlib import Path
|
@@ -1679,16 +1680,22 @@ def get_importable_stdlib_modules() -> set[str]:
|
1679 | 1680 | all_stdlib_modules = sys.stdlib_module_names
|
1680 | 1681 | else:
|
1681 | 1682 | all_stdlib_modules = set(sys.builtin_module_names)
|
1682 |
| - python_exe_dir = Path(sys.executable).parent |
| 1683 | + modules_by_finder: defaultdict[importlib.machinery.FileFinder, set[str]] = defaultdict(set) |
1683 | 1684 | for m in pkgutil.iter_modules():
|
1684 |
| - finder = m.module_finder |
1685 |
| - if isinstance(finder, importlib.machinery.FileFinder): |
1686 |
| - finder_path = Path(finder.path) |
1687 |
| - if ( |
1688 |
| - python_exe_dir in finder_path.parents |
1689 |
| - and "site-packages" not in finder_path.parts |
1690 |
| - ): |
1691 |
| - all_stdlib_modules.add(m.name) |
| 1685 | + if isinstance(m.module_finder, importlib.machinery.FileFinder): |
| 1686 | + modules_by_finder[m.module_finder].add(m.name) |
| 1687 | + for finder, module_group in modules_by_finder.items(): |
| 1688 | + if ( |
| 1689 | + "site-packages" not in Path(finder.path).parents |
| 1690 | + # if "_queue" is present, it's most likely the module finder |
| 1691 | + # for stdlib extension modules; |
| 1692 | + # if "queue" is present, it's most likely the module finder |
| 1693 | + # for pure-Python stdlib modules. |
| 1694 | + # In either case, we'll want to add all the modules that the finder has to offer us. |
| 1695 | + # This is a bit hacky, but seems to work well in a cross-platform way. |
| 1696 | + and {"_queue", "queue"} & module_group |
| 1697 | + ): |
| 1698 | + all_stdlib_modules.update(module_group) |
1692 | 1699 |
|
1693 | 1700 | importable_stdlib_modules: set[str] = set()
|
1694 | 1701 | for module_name in all_stdlib_modules:
|
@@ -1719,13 +1726,25 @@ def get_importable_stdlib_modules() -> set[str]:
|
1719 | 1726 | # The idlelib.* submodules are similarly annoying in opening random tkinter windows,
|
1720 | 1727 | # and we're unlikely to ever add stubs for idlelib in typeshed
|
1721 | 1728 | # (see discussion in https://github.com/python/typeshed/pull/9193)
|
1722 |
| - if submodule_name.endswith(".__main__") or submodule_name.startswith("idlelib."): |
| 1729 | + # |
| 1730 | + # test.* modules do weird things like raising exceptions in __del__ methods, |
| 1731 | + # leading to unraisable exceptions being logged to the terminal |
| 1732 | + # as a warning at the end of the stubtest run |
| 1733 | + if ( |
| 1734 | + submodule_name.endswith(".__main__") |
| 1735 | + or submodule_name.startswith("idlelib.") |
| 1736 | + or submodule_name.startswith("test.") |
| 1737 | + ): |
1723 | 1738 | continue
|
1724 | 1739 |
|
1725 | 1740 | try:
|
1726 | 1741 | silent_import_module(submodule_name)
|
| 1742 | + except KeyboardInterrupt: |
| 1743 | + raise |
1727 | 1744 | # importing multiprocessing.popen_forkserver on Windows raises AttributeError...
|
1728 |
| - except Exception: |
| 1745 | + # some submodules also appear to raise SystemExit as well on some Python versions |
| 1746 | + # (not sure exactly which) |
| 1747 | + except BaseException: |
1729 | 1748 | continue
|
1730 | 1749 | else:
|
1731 | 1750 | importable_stdlib_modules.add(submodule_name)
|
|
0 commit comments