|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +import inspect |
| 4 | +import pkgutil |
| 5 | +import sys |
| 6 | + |
| 7 | +SEEN_MODS = set() |
| 8 | + |
| 9 | + |
| 10 | +def walk_pkgutil(mod_name, mod, io): |
| 11 | + for pkg in pkgutil.walk_packages(mod.__path__, mod_name + "."): |
| 12 | + if pkg.name in SEEN_MODS: |
| 13 | + continue |
| 14 | + else: |
| 15 | + # We don't recurse here because `walk_packages` takes care of |
| 16 | + # it for us. |
| 17 | + SEEN_MODS.add(pkg.name) |
| 18 | + print(pkg.name, file=io) |
| 19 | + |
| 20 | + |
| 21 | +def walk_naive(mod_name, mod, io): |
| 22 | + for attr in dir(mod): |
| 23 | + attr_obj = getattr(mod, attr, None) |
| 24 | + # Shouldn't happen, but who knows. |
| 25 | + if attr_obj is None: |
| 26 | + continue |
| 27 | + |
| 28 | + # If this member isn't a module, skip it. |
| 29 | + if not inspect.ismodule(attr_obj): |
| 30 | + continue |
| 31 | + |
| 32 | + # To filter "real" submodules from re-exports, we try |
| 33 | + # and import the submodule by its qualified name. |
| 34 | + # If the import fails, we know it's a re-exported module. |
| 35 | + try: |
| 36 | + submod_name = mod_name + "." + attr |
| 37 | + __import__(submod_name) |
| 38 | + walk(submod_name, io) |
| 39 | + except ImportError: |
| 40 | + # ...but sometimes we do want to include re-exports, since |
| 41 | + # they might be things like "accelerator" modules that don't |
| 42 | + # appear anywhere else. |
| 43 | + # For example, `_bz2` might appear as a re-export. |
| 44 | + try: |
| 45 | + # Again, try and import to avoid module-looking object |
| 46 | + # that don't actually appear on disk. Experimentally, |
| 47 | + # there are a few of these (like "TK"). |
| 48 | + __import__(attr) |
| 49 | + walk(attr, io) |
| 50 | + except ImportError: |
| 51 | + continue |
| 52 | + |
| 53 | + |
| 54 | +def walk(mod_name, io): |
| 55 | + if mod_name in SEEN_MODS: |
| 56 | + return |
| 57 | + else: |
| 58 | + SEEN_MODS.add(mod_name) |
| 59 | + print(mod_name, file=io) |
| 60 | + |
| 61 | + # Try and import it. |
| 62 | + try: |
| 63 | + mod = __import__(mod_name) |
| 64 | + |
| 65 | + if hasattr(mod, "__path__"): |
| 66 | + walk_pkgutil(mod_name, mod, io) |
| 67 | + else: |
| 68 | + walk_naive(mod_name, mod, io) |
| 69 | + |
| 70 | + except ImportError: |
| 71 | + pass |
| 72 | + |
| 73 | + |
| 74 | +if __name__ == "__main__": |
| 75 | + output = sys.argv[1] |
| 76 | + |
| 77 | + with open(output, mode="w") as io: |
| 78 | + for mod_name in sys.builtin_module_names: |
| 79 | + walk(mod_name, io) |
| 80 | + |
| 81 | + if hasattr(sys, "stdlib_module_names"): |
| 82 | + for mod_name in sys.stdlib_module_names: |
| 83 | + walk(mod_name, io) |
| 84 | + else: |
| 85 | + for mod_name in sys.stdin: |
| 86 | + walk(mod_name.rstrip("\n"), io) |
0 commit comments