|
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