fix: suppress graspologic ANSI output that corrupts PowerShell scroll buffer

* fix: suppress graspologic ANSI output that breaks PowerShell scrolling

graspologic's leiden() emits ANSI escape sequences (progress bars,
colored warnings) that corrupt PowerShell 5.1's scroll buffer on
Windows, disabling vertical scrolling. Redirect stdout/stderr to
StringIO during leiden() calls to prevent any escape codes from
reaching the terminal.

Add 2 tests verifying cluster() produces no stdout/stderr output.

Fixes #19

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add PowerShell troubleshooting section to Windows skill

Document the PowerShell 5.1 scrolling issue and provide 4
workarounds: upgrade graphify, use Windows Terminal, reset
terminal, or uninstall graspologic to use Louvain fallback.

Fixes #19

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
azizur100389
2026-04-08 19:40:10 +01:00
committed by GitHub
co-authored by Claude Opus 4.6
parent ba7c395ce3
commit 22f79db72f
3 changed files with 65 additions and 1 deletions
+28 -1
View File
@@ -1,17 +1,44 @@
"""Community detection on NetworkX graphs. Uses Leiden (graspologic) if available, falls back to Louvain (networkx). Splits oversized communities. Returns cohesion scores."""
from __future__ import annotations
import contextlib
import io
import os
import sys
import networkx as nx
def _suppress_output():
"""Context manager to suppress stdout/stderr during library calls.
graspologic's leiden() emits ANSI escape sequences (progress bars,
colored warnings) that corrupt PowerShell 5.1's scroll buffer on
Windows (see issue #19). Redirecting stdout/stderr to devnull during
the call prevents this without losing any graphify output.
"""
return contextlib.redirect_stdout(io.StringIO())
def _partition(G: nx.Graph) -> dict[str, int]:
"""Run community detection. Returns {node_id: community_id}.
Tries Leiden (graspologic) first — best quality.
Falls back to Louvain (built into networkx) if graspologic is not installed.
Output from graspologic is suppressed to prevent ANSI escape codes
from corrupting terminal scroll buffers on Windows PowerShell 5.1.
"""
try:
from graspologic.partition import leiden
return leiden(G)
# Suppress graspologic output to prevent ANSI escape codes from
# corrupting PowerShell 5.1 scroll buffer (issue #19)
old_stderr = sys.stderr
try:
sys.stderr = io.StringIO()
with _suppress_output():
result = leiden(G)
finally:
sys.stderr = old_stderr
return result
except ImportError:
pass
+13
View File
@@ -1202,6 +1202,19 @@ graphify claude uninstall # remove the section
---
## Troubleshooting
### PowerShell 5.1: Vertical scrolling stops working
If vertical scrolling breaks in PowerShell after running graphify, this is caused by ANSI escape sequences from the `graspologic` library. Graphify v0.3.10+ suppresses this output, but if you still see the issue:
1. **Upgrade graphify**: `pip install --upgrade graphifyy`
2. **Use Windows Terminal** instead of the legacy PowerShell console — Windows Terminal handles ANSI codes correctly
3. **Reset your terminal**: close and reopen PowerShell
4. **Skip graspologic**: uninstall it (`pip uninstall graspologic`) and graphify will fall back to NetworkX's built-in Louvain algorithm, which produces no ANSI output
---
## Honesty Rules
- Never invent an edge. If unsure, use AMBIGUOUS.
+24
View File
@@ -1,4 +1,5 @@
import json
import sys
import networkx as nx
from pathlib import Path
from graphify.build import build_from_json
@@ -50,3 +51,26 @@ def test_score_all_keys_match_communities():
communities = cluster(G)
scores = score_all(G, communities)
assert set(scores.keys()) == set(communities.keys())
def test_cluster_does_not_write_to_stdout(capsys):
"""Clustering should not emit ANSI escape codes or other output.
graspologic's leiden() can emit ANSI escape sequences that break
PowerShell 5.1's scroll buffer on Windows (issue #19). The output
suppression in _partition() should prevent any output from leaking.
"""
G = make_graph()
cluster(G)
captured = capsys.readouterr()
assert captured.out == "", f"cluster() wrote to stdout: {captured.out!r}"
def test_cluster_does_not_write_to_stderr(capsys):
"""Same as above but for stderr — ANSI codes can go to either stream."""
G = make_graph()
cluster(G)
captured = capsys.readouterr()
# Allow logging output (starts with [graphify]) but no raw ANSI codes
for line in captured.err.splitlines():
assert "\x1b" not in line, f"cluster() wrote ANSI to stderr: {line!r}"