Skip to content

Instantly share code, notes, and snippets.

@zooba
Created March 11, 2019 01:50
Show Gist options
  • Save zooba/f34089baed4397f6be1a4af8b301720e to your computer and use it in GitHub Desktop.
Save zooba/f34089baed4397f6be1a4af8b301720e to your computer and use it in GitHub Desktop.
Tool for seeing which Python stdlib modules have dependencies on others
import ast
import json
import sys
import sysconfig
from pathlib import Path
def remove(data, key):
removed = {key}
removed.update(k for k in data if k.startswith(key + "."))
report = {}
any_removed = bool(removed)
while any_removed:
for k in removed:
data.pop(k, None)
any_removed = False
for k, v in data.items():
cause = removed & set(v)
if not cause:
continue
any_removed = True
report[k] = cause
removed.add(k)
removed.update(k2 for k2 in data if k2.startswith(f"{k}."))
return report
def find_deps(file):
try:
with open(file, "rb") as f:
tree = ast.parse(f.read(), str(file))
except SyntaxError:
return
# for n in ast.walk(tree):
for n in ast.iter_child_nodes(tree):
if isinstance(n, ast.ImportFrom):
yield n.module
elif isinstance(n, ast.Import):
yield from (nom.name for nom in n.names)
def module_name(root, file):
p = file.with_suffix("").relative_to(root)
parts = p.parts[:-1] if p.parts[-1] == "__init__" else p.parts
return ".".join(parts)
SKIP_DIRS = {"test", "tests", "site-packages", "idle_test"}
def search(root):
found = {}
for p in Path(root).resolve().rglob("**/*.py"):
if SKIP_DIRS & set(p.parts):
continue
deps = set(find_deps(p))
deps.discard(None)
found[module_name(root, p)] = sorted(deps)
return found
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: try-remove MODULE ...")
print()
sys.exit(1)
try:
with open("try-remove.json", "r", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
print("Scanning sysconfig.get_path('stdlib')")
print(" -", sysconfig.get_path("stdlib"))
print(" - caching to to", Path("try-remove.json").resolve())
data = search(sysconfig.get_path("stdlib"))
print()
with open("try-remove.json", "w", encoding="utf-8") as f:
json.dump(data, f)
report = {}
for m in sys.argv[1:]:
report.update(remove(data, m))
print("Removed:")
for k in sorted(report):
v = report[k]
print(f" {k} because {sorted(v)}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment