Skip to main content

python/depanalysis.py

1#!/usr/bin/env python3
2"""
3Analyse the dependencies installed in every Python virtualenv on my computer.
5This gets a complete list of dependencies in each environment, then
6prints a list of dependencies and the versions installed.
7"""
9from collections import Counter, defaultdict
10from pathlib import Path
11import re
12import subprocess
14from chives.text import coloured
16if __name__ == "__main__":
17 venv_path = Path("/tmp/depanalysis/venv.txt")
18 venv_path.parent.mkdir(exist_ok=True)
20 output = subprocess.check_output(
21 "get_all_venv_deps", text=True, stderr=subprocess.DEVNULL
22 )
23 venv_path.write_text(output)
25 all_versions = defaultdict(list)
26 for line in output.splitlines():
27 if not re.search(r"==[0-9]", line):
28 continue
30 package, version = line.strip().split("==")
31 all_versions[package].append(version)
33 for package, versions in sorted(all_versions.items(), key=lambda kv: len(kv[1])):
34 tally = Counter(versions)
36 if len(tally) == 1:
37 print(f"{len(versions):3d} {package} {versions[0]}")
38 else:
39 # Break each version into a tuple of ints, then sort them.
40 # This will break for non-numeric versions but it's fine for
41 # now, and makes it easy to spot outdated packages.
42 sorted_versions = sorted(
43 tally.items(), key=lambda kv: tuple([int(p) for p in kv[0].split(".")])
44 )
45 version_info = ", ".join(
46 f"{v_str} ({count})" for v_str, count in sorted_versions
47 )
48 print(f"{len(versions):3d} {package} {coloured(version_info, 'blue')}")
50 subprocess.check_call(["mate", str(venv_path)])
52 unique_versions = sum(len(set(v)) for v in all_versions.values())
53 print(f"{len(all_versions)} packages, {unique_versions} unique versions")