Skip to main content

python/depanalysis: print info about the different versions

ID
0d880d0
date
2026-07-26 19:34:38+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
b0cd4e7
message
python/depanalysis: print info about the different versions
changed files
4 files, 50 additions, 19 deletions

Changed files

config.fish (6778 → 6829)

diff --git a/config.fish b/config.fish
index 333d52d..203e623 100644
--- a/config.fish
+++ b/config.fish
@@ -192,6 +192,7 @@ __create_python_script_alias images/reborder.py
 __create_python_script_alias images/squarify.py
 __create_python_script_alias images/srgbify.py
 __create_python_script_alias images/tint_image.py
+__create_python_script_alias python/depanalysis.py
 __create_python_script_alias tailscale/tsapi.py
 __create_python_script_alias text/fix_twemoji.py
 __create_python_script_alias text/fix_twitter_thread.py

python/README.md (3025 → 3034)

diff --git a/python/README.md b/python/README.md
index 0863d4e..a0aab55 100644
--- a/python/README.md
+++ b/python/README.md
@@ -18,7 +18,7 @@ folder_name = "python"
 
 scripts = [
     {
-        "usage": "depanalysis",
+        "usage": "depanalysis.py",
         "description": """
         get a summary of every Python version installed in every Python virtualenv on my computer.
         """,
@@ -54,8 +54,8 @@ cog_helpers.create_description_table(folder_name=folder_name, scripts=scripts)
 ]]]-->
 <dl>
   <dt>
-    <a href="https://github.com/alexwlchan/scripts/blob/main/python/depanalysis">
-      <code>depanalysis</code>
+    <a href="https://github.com/alexwlchan/scripts/blob/main/python/depanalysis.py">
+      <code>depanalysis.py</code>
     </a>
   </dt>
   <dd>
@@ -107,4 +107,4 @@ cog_helpers.create_description_table(folder_name=folder_name, scripts=scripts)
     A wrapper around `uv pip sync`. You don't need to call this directly.
   </dd>
 </dl>
-<!-- [[[end]]] (sum: WIjqpb60M8) -->
+<!-- [[[end]]] (sum: uidUz8WCul) -->

python/depanalysis (459 → 0)

diff --git a/python/depanalysis b/python/depanalysis
deleted file mode 100755
index a2e5118..0000000
--- a/python/depanalysis
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-set -o errexit
-set -o nounset
-
-mkdir -p /tmp/depanalysis
-cd /tmp/depanalysis
-get_all_venv_deps > venv.txt
-grep '==[0-9]' venv.txt | tr '==' ' ' | awk '{print $1}' | tally
-
-UNIQUE_LIBRARIES=$(grep '==[0-9]' venv.txt | tr '==' ' ' | awk '{print $1}' | tally | wc -l | trim)
-UNIQUE_VERSIONS=$(grep '==[0-9]' /tmp/depanalysis/venv.txt | tally | wc -l | trim)
-echo "== $UNIQUE_LIBRARIES libraries, $UNIQUE_VERSIONS versions =="
-
-mate venv.txt

python/depanalysis.py (0 → 1370)

diff --git a/python/depanalysis.py b/python/depanalysis.py
new file mode 100755
index 0000000..148854a
--- /dev/null
+++ b/python/depanalysis.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+"""
+Analyse the dependencies installed in every Python virtualenv on my computer.
+
+This gets a complete list of dependencies in each environment, then
+prints a list of dependencies and the versions installed.
+"""
+
+from collections import Counter, defaultdict
+from pathlib import Path
+import re
+import subprocess
+
+from chives.text import coloured
+
+
+if __name__ == "__main__":
+    venv_path = Path("/tmp/depanalysis/venv.txt")
+    venv_path.parent.mkdir(exist_ok=True)
+
+    output = subprocess.check_output(
+        "get_all_venv_deps", text=True, stderr=subprocess.DEVNULL
+    )
+    venv_path.write_text(output)
+
+    all_versions = defaultdict(list)
+    for line in output.splitlines():
+        if not re.search(r"==[0-9]", line):
+            continue
+
+        package, version = line.strip().split("==")
+        all_versions[package].append(version)
+
+    for package, versions in sorted(all_versions.items(), key=lambda kv: len(kv[1])):
+        tally = Counter(versions)
+
+        if len(tally) == 1:
+            print(f"{len(versions):3d}  {package} {versions[0]}")
+        else:
+            version_info = ", ".join(
+                f"{v_str} ({count})" for v_str, count in tally.most_common()
+            )
+            print(f"{len(versions):3d}  {package} {coloured(version_info, 'blue')}")
+
+    subprocess.check_call(["mate", str(venv_path)])