Skip to content

refactor(mesh-brain): replace graspologic Leiden with NetworkX Louvain — unblock numpy 2.x + py3.13 (#10524) - #10530

Merged
mrveiss merged 3 commits into
Dev_new_guifrom
issue-10524
Jun 27, 2026
Merged

mrveiss merged 3 commits into
Dev_new_guifrom
issue-10524

Conversation

@mrveiss

@mrveiss mrveiss commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Thinking Path

Part of #10524 (Task 1). The repo can't unify on a single latest numpy because graspologic 3.4.4 (latest, no numpy-2 release even in dev) hard-pins numpy<2.0.0 and requires_python <3.13 — silently capping the backend a major version behind and blocking the py3.14 migration. graspologic was used in exactly one place: two leiden(G, trials=N) calls in community_clusterer.py. NetworkX (already a dependency) ships weight-aware Louvain with the same {node: community_id} shape, so the swap removes the blocker without adding a package.

What Changed

  • community_clusterer.py — new _detect_communities() helper using networkx.algorithms.community.louvain_communities (seeded for determinism); both Leiden call sites now route through it; graspologic imports removed. Return contract unchanged.
  • requirements.txt — removed graspologic>=3.4.4; lifted the opencv-python-headless<4.11 cap (numpy>=2 is now resolvable in the backend).
  • lifespan.py — removed the dead except ImportError → "pip install graspologic" → sleep 24h branch. NetworkX is a hard dependency, so that condition can no longer occur; the generic except Exception still handles real failures.
  • tests — removed the graspologic sys.modules stubs from community_clusterer_test.py and mesh_db_adapter_test.py, plus the two tests asserting the now-removed ImportError/24h-pause behavior. All clustering assertions retained and now run against real Louvain.

Verification

$ python3 -m pytest services/mesh_brain/community_clusterer_test.py \
                     services/mesh_brain/mesh_db_adapter_test.py -q
31 passed in 0.89s
  • Triangle → 1 community → 1 centroid; two disconnected triangles → 2 communities → 2 centroids — both hold under real Louvain.
  • grep -rn graspologic --include=*.py → only explanatory comments remain (no code refs).
  • py_compile clean on all changed files.

Follow-ups (Task 2/3 of #10524): add constraints/shared.txt as the single numpy source of truth referenced by every component; CI guard against version re-drift across portable/co-locatable roles.

Model Used

Claude Opus 4.8 (1M context)

…n — unblock numpy 2.x + py3.13 (#10524)

graspologic 3.4.4 (latest) hard-pins numpy<2.0 and requires Python <3.13,
silently capping the backend a major numpy version behind and blocking the
py3.14 migration. It was used in exactly one place — two leiden() calls in
community_clusterer.py. Swap to NetworkX's built-in Louvain (already a
dependency, weight-aware, deterministic via seed) so no package is added.

- community_clusterer: _detect_communities() helper via louvain_communities,
  same {node: community_id} contract; drop graspologic imports
- requirements: remove graspologic; lift opencv-python-headless <4.11 cap
  (numpy>=2 now resolvable in backend)
- lifespan: drop dead graspologic-missing ImportError/24h-pause branch
  (NetworkX is a hard dep; generic handler covers real failures)
- tests: remove graspologic stubs + ImportError-path tests (behavior gone)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

@mrveiss
mrveiss merged commit 47c8633 into Dev_new_gui Jun 27, 2026
25 of 27 checks passed
@mrveiss
mrveiss deleted the issue-10524 branch June 27, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant