zenus-visualization 0.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: zenus-visualization
3
+ Version: 0.6.1
4
+ Summary: Data visualization system for Zenus
5
+ Author: Zeni
6
+ Requires-Python: >=3.10,<4.0
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Dist: rich (>=13.7.0,<14.0.0)
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Zenus Visualization
17
+
18
+ Automatic data visualization system for Zenus.
19
+
20
+ ## Features
21
+
22
+ - **Auto-detection**: Automatically detects data types and chooses the best visualization
23
+ - **Rich tables**: Beautiful tables for structured data
24
+ - **Progress bars**: Visual indicators for percentages and resource usage
25
+ - **File trees**: Hierarchical file and directory displays
26
+ - **Syntax highlighting**: Code and JSON with color coding
27
+
28
+ ## Usage
29
+
30
+ ```python
31
+ from zenus_visualization import Visualizer
32
+
33
+ # Automatically visualize any data
34
+ Visualizer.visualize(data)
35
+
36
+ # With context hint
37
+ Visualizer.visualize(data, context="process_list")
38
+ ```
39
+
40
+ ## Supported Data Types
41
+
42
+ - Process lists
43
+ - Disk usage stats
44
+ - System resource summaries
45
+ - File listings
46
+ - JSON/structured data
47
+ - Key-value pairs
48
+ - Plain text (fallback)
49
+
@@ -0,0 +1,33 @@
1
+ # Zenus Visualization
2
+
3
+ Automatic data visualization system for Zenus.
4
+
5
+ ## Features
6
+
7
+ - **Auto-detection**: Automatically detects data types and chooses the best visualization
8
+ - **Rich tables**: Beautiful tables for structured data
9
+ - **Progress bars**: Visual indicators for percentages and resource usage
10
+ - **File trees**: Hierarchical file and directory displays
11
+ - **Syntax highlighting**: Code and JSON with color coding
12
+
13
+ ## Usage
14
+
15
+ ```python
16
+ from zenus_visualization import Visualizer
17
+
18
+ # Automatically visualize any data
19
+ Visualizer.visualize(data)
20
+
21
+ # With context hint
22
+ Visualizer.visualize(data, context="process_list")
23
+ ```
24
+
25
+ ## Supported Data Types
26
+
27
+ - Process lists
28
+ - Disk usage stats
29
+ - System resource summaries
30
+ - File listings
31
+ - JSON/structured data
32
+ - Key-value pairs
33
+ - Plain text (fallback)
@@ -0,0 +1,18 @@
1
+ [build-system]
2
+ requires = ["poetry-core"]
3
+ build-backend = "poetry.core.masonry.api"
4
+
5
+ [tool.poetry]
6
+ name = "zenus-visualization"
7
+ version = "0.6.1"
8
+ description = "Data visualization system for Zenus"
9
+ authors = ["Zeni"]
10
+ readme = "README.md"
11
+ packages = [{include = "zenus_visualization", from = "src"}]
12
+
13
+ [tool.poetry.dependencies]
14
+ python = "^3.10"
15
+ rich = "^13.7.0"
16
+
17
+ [tool.poetry.group.dev.dependencies]
18
+ pytest = "^7.4.0"
@@ -0,0 +1,8 @@
1
+ """
2
+ Zenus Visualization - Data Visualization System
3
+ """
4
+
5
+ from zenus_visualization.visualizer import Visualizer
6
+
7
+ __all__ = ["Visualizer"]
8
+ __version__ = "0.1.0"
@@ -0,0 +1,381 @@
1
+ """
2
+ Main Visualizer - Automatic Data Visualization
3
+
4
+ Detects data types and renders beautiful visualizations automatically.
5
+ """
6
+
7
+ import re
8
+ from typing import Dict, List, Optional, Union
9
+ from rich.console import Console
10
+ from rich.table import Table
11
+ from rich.panel import Panel
12
+ from rich.syntax import Syntax
13
+ from rich import box
14
+ from rich.tree import Tree
15
+ import json
16
+
17
+
18
+ console = Console()
19
+
20
+
21
+ class Visualizer:
22
+ """
23
+ Automatically visualizes data in the most appropriate format
24
+
25
+ Detects:
26
+ - Tables (lists of dicts, process lists, file listings)
27
+ - Progress/percentages (disk usage, memory usage)
28
+ - JSON/structured data
29
+ - Code diffs
30
+ - File trees
31
+ - Key-value pairs
32
+ - Plain text (fallback)
33
+ """
34
+
35
+ @staticmethod
36
+ def visualize(data: Union[str, Dict, List], context: Optional[str] = None) -> None:
37
+ """
38
+ Main entry point - automatically detects type and visualizes
39
+
40
+ Args:
41
+ data: Data to visualize (string, dict, list)
42
+ context: Optional context (e.g., "file_list", "process_list", "disk_usage")
43
+ """
44
+ if isinstance(data, dict):
45
+ Visualizer._visualize_dict(data, context)
46
+ elif isinstance(data, list):
47
+ Visualizer._visualize_list(data, context)
48
+ elif isinstance(data, str):
49
+ Visualizer._visualize_string(data, context)
50
+ else:
51
+ # Fallback to string representation
52
+ console.print(f" → {str(data)}", style="dim")
53
+
54
+ @staticmethod
55
+ def _visualize_string(data: str, context: Optional[str]) -> None:
56
+ """Visualize string data with smart detection"""
57
+
58
+ # Check for process list pattern
59
+ if "PID" in data and "%" in data:
60
+ Visualizer._visualize_process_list(data)
61
+ return
62
+
63
+ # Check for disk usage pattern
64
+ if "GB" in data and ("used" in data.lower() or "free" in data.lower()):
65
+ Visualizer._visualize_disk_usage(data)
66
+ return
67
+
68
+ # Check for CPU/Memory/Disk summary
69
+ if "CPU:" in data and "Memory:" in data and "Disk:" in data:
70
+ Visualizer._visualize_system_summary(data)
71
+ return
72
+
73
+ # Check for file list pattern (filenames with sizes)
74
+ if context == "file_list" or re.search(r'\.(py|txt|md|json|yaml)', data):
75
+ Visualizer._visualize_file_list(data)
76
+ return
77
+
78
+ # Check for percentage/progress
79
+ if "%" in data:
80
+ Visualizer._visualize_percentage(data)
81
+ return
82
+
83
+ # Check for JSON
84
+ if data.strip().startswith('{') or data.strip().startswith('['):
85
+ try:
86
+ parsed = json.loads(data)
87
+ Visualizer._visualize_dict(parsed, context)
88
+ return
89
+ except Exception:
90
+ pass
91
+
92
+ # Check for key-value pairs
93
+ if "\n" in data and ":" in data:
94
+ Visualizer._visualize_key_value(data)
95
+ return
96
+
97
+ # Fallback: plain text with formatting
98
+ console.print(f" → {data}", style="cyan")
99
+
100
+ @staticmethod
101
+ def _visualize_process_list(data: str) -> None:
102
+ """Visualize process list as a rich table"""
103
+ lines = data.strip().split("\n")
104
+
105
+ table = Table(
106
+ title="🖥️ Processes",
107
+ box=box.ROUNDED,
108
+ show_header=True,
109
+ header_style="bold magenta"
110
+ )
111
+
112
+ table.add_column("PID", style="cyan", justify="right", width=8)
113
+ table.add_column("Name", style="green")
114
+ table.add_column("Memory", style="yellow", justify="right", width=10)
115
+ table.add_column("Usage Bar", width=20)
116
+
117
+ for line in lines:
118
+ # Parse: "PID 1009: openclaw-gateway (12.6% mem)"
119
+ match = re.match(r'PID\s+(\d+):\s+(.+?)\s+\(([0-9.]+)%\s+mem\)', line)
120
+ if match:
121
+ pid, name, mem_pct = match.groups()
122
+ mem_float = float(mem_pct)
123
+
124
+ # Create visual bar
125
+ bar_width = int(mem_float / 5) # Scale to 20 chars max
126
+ bar = "█" * bar_width + "░" * (20 - bar_width)
127
+
128
+ # Color code by usage
129
+ if mem_float > 10:
130
+ mem_style = "bold red"
131
+ elif mem_float > 5:
132
+ mem_style = "bold yellow"
133
+ else:
134
+ mem_style = "bold green"
135
+
136
+ table.add_row(
137
+ pid,
138
+ name,
139
+ f"[{mem_style}]{mem_pct}%[/{mem_style}]",
140
+ f"[{mem_style}]{bar}[/{mem_style}]"
141
+ )
142
+
143
+ console.print(table)
144
+
145
+ @staticmethod
146
+ def _visualize_disk_usage(data: str) -> None:
147
+ """Visualize disk usage with progress bar"""
148
+ # Parse: "Disk /tmp: 110.0GB used / 260.0GB total (42.3% used, 136.8GB free)"
149
+ match = re.search(
150
+ r'Disk\s+(.+?):\s+([0-9.]+)GB\s+used\s+/\s+([0-9.]+)GB\s+total\s+\(([0-9.]+)%\s+used,\s+([0-9.]+)GB\s+free\)',
151
+ data
152
+ )
153
+
154
+ if not match:
155
+ console.print(f" → {data}", style="cyan")
156
+ return
157
+
158
+ path, used, total, pct, free = match.groups()
159
+ used_f, total_f, pct_f, free_f = float(used), float(total), float(pct), float(free)
160
+
161
+ # Color code based on usage
162
+ if pct_f > 90:
163
+ color = "red"
164
+ emoji = "🔴"
165
+ elif pct_f > 75:
166
+ color = "yellow"
167
+ emoji = "🟡"
168
+ else:
169
+ color = "green"
170
+ emoji = "🟢"
171
+
172
+ # Create visual bar
173
+ bar_width = 40
174
+ filled = int((pct_f / 100) * bar_width)
175
+ bar = "█" * filled + "░" * (bar_width - filled)
176
+
177
+ # Build panel content
178
+ content = f"""
179
+ [bold cyan]Path:[/bold cyan] {path}
180
+
181
+ [bold {color}]{emoji} {pct_f:.1f}% Used[/bold {color}]
182
+
183
+ [{color}]{bar}[/{color}]
184
+
185
+ [bold]Used:[/bold] {used_f:.1f} GB [bold]Free:[/bold] {free_f:.1f} GB [bold]Total:[/bold] {total_f:.1f} GB
186
+ """
187
+
188
+ panel = Panel(
189
+ content.strip(),
190
+ title="💾 Disk Usage",
191
+ border_style=color,
192
+ box=box.ROUNDED
193
+ )
194
+
195
+ console.print(panel)
196
+
197
+ @staticmethod
198
+ def _visualize_system_summary(data: str) -> None:
199
+ """Visualize system resource summary"""
200
+ lines = data.strip().split("\n")
201
+
202
+ table = Table(
203
+ title="🖥️ System Resources",
204
+ box=box.ROUNDED,
205
+ show_header=True,
206
+ header_style="bold magenta"
207
+ )
208
+
209
+ table.add_column("Resource", style="cyan", width=12)
210
+ table.add_column("Usage", style="yellow", justify="right", width=15)
211
+ table.add_column("Visual", width=25)
212
+ table.add_column("Details", style="dim")
213
+
214
+ for line in lines:
215
+ if line.startswith("CPU:"):
216
+ # Parse: "CPU: 5.1% used (2 cores)"
217
+ match = re.search(r'CPU:\s+([0-9.]+)%\s+used\s+\((\d+)\s+cores?\)', line)
218
+ if match:
219
+ pct, cores = match.groups()
220
+ pct_f = float(pct)
221
+ bar = "█" * int(pct_f / 4) + "░" * (25 - int(pct_f / 4))
222
+
223
+ color = "red" if pct_f > 80 else "yellow" if pct_f > 50 else "green"
224
+
225
+ table.add_row(
226
+ "CPU",
227
+ f"[bold {color}]{pct}%[/bold {color}]",
228
+ f"[{color}]{bar}[/{color}]",
229
+ f"{cores} cores"
230
+ )
231
+
232
+ elif line.startswith("Memory:"):
233
+ # Parse: "Memory: 1.5GB / 3.7GB (52.9% used, 1.7GB free)"
234
+ match = re.search(r'Memory:\s+([0-9.]+)GB\s+/\s+([0-9.]+)GB\s+\(([0-9.]+)%\s+used,\s+([0-9.]+)GB\s+free\)', line)
235
+ if match:
236
+ used, total, pct, free = match.groups()
237
+ pct_f = float(pct)
238
+ bar = "█" * int(pct_f / 4) + "░" * (25 - int(pct_f / 4))
239
+
240
+ color = "red" if pct_f > 90 else "yellow" if pct_f > 70 else "green"
241
+
242
+ table.add_row(
243
+ "Memory",
244
+ f"[bold {color}]{pct}%[/bold {color}]",
245
+ f"[{color}]{bar}[/{color}]",
246
+ f"{used}GB / {total}GB"
247
+ )
248
+
249
+ elif line.startswith("Disk:"):
250
+ # Parse: "Disk: 110.0GB / 260.0GB (42.3% used, 136.8GB free)"
251
+ match = re.search(r'Disk:\s+([0-9.]+)GB\s+/\s+([0-9.]+)GB\s+\(([0-9.]+)%\s+used,\s+([0-9.]+)GB\s+free\)', line)
252
+ if match:
253
+ used, total, pct, free = match.groups()
254
+ pct_f = float(pct)
255
+ bar = "█" * int(pct_f / 4) + "░" * (25 - int(pct_f / 4))
256
+
257
+ color = "red" if pct_f > 90 else "yellow" if pct_f > 75 else "green"
258
+
259
+ table.add_row(
260
+ "Disk",
261
+ f"[bold {color}]{pct}%[/bold {color}]",
262
+ f"[{color}]{bar}[/{color}]",
263
+ f"{used}GB / {total}GB"
264
+ )
265
+
266
+ console.print(table)
267
+
268
+ @staticmethod
269
+ def _visualize_file_list(data: str) -> None:
270
+ """Visualize file listing"""
271
+ # Try to parse as list first
272
+ if data.startswith('[') and data.endswith(']'):
273
+ try:
274
+ files = eval(data) # Safe here since we control the input
275
+ if isinstance(files, list):
276
+ tree = Tree("📁 Files", guide_style="dim")
277
+
278
+ for item in files:
279
+ if isinstance(item, str):
280
+ # Detect file vs directory
281
+ if '.' in item:
282
+ tree.add(f"📄 [cyan]{item}[/cyan]")
283
+ else:
284
+ tree.add(f"📁 [green]{item}/[/green]")
285
+
286
+ console.print(tree)
287
+ return
288
+ except Exception:
289
+ pass
290
+
291
+ # Fallback to plain display
292
+ console.print(f" → {data}", style="cyan")
293
+
294
+ @staticmethod
295
+ def _visualize_percentage(data: str) -> None:
296
+ """Visualize percentage values"""
297
+ console.print(f" → {data}", style="cyan")
298
+
299
+ @staticmethod
300
+ def _visualize_key_value(data: str) -> None:
301
+ """Visualize key-value pairs as a table"""
302
+ lines = [line.strip() for line in data.split("\n") if line.strip() and ":" in line]
303
+
304
+ if len(lines) < 2:
305
+ console.print(f" → {data}", style="cyan")
306
+ return
307
+
308
+ table = Table(box=box.SIMPLE, show_header=False)
309
+ table.add_column("Key", style="cyan", width=20)
310
+ table.add_column("Value", style="white")
311
+
312
+ for line in lines:
313
+ if ":" in line:
314
+ key, value = line.split(":", 1)
315
+ table.add_row(key.strip(), value.strip())
316
+
317
+ console.print(table)
318
+
319
+ @staticmethod
320
+ def _visualize_dict(data: Dict, context: Optional[str]) -> None:
321
+ """Visualize dictionary as formatted JSON or table"""
322
+ # Try to display as table if simple key-value pairs
323
+ if all(isinstance(v, (str, int, float, bool, type(None))) for v in data.values()):
324
+ table = Table(box=box.SIMPLE, show_header=False)
325
+ table.add_column("Key", style="cyan", width=20)
326
+ table.add_column("Value", style="white")
327
+
328
+ for key, value in data.items():
329
+ table.add_row(str(key), str(value))
330
+
331
+ console.print(table)
332
+ else:
333
+ # Complex dict - show as formatted JSON
334
+ syntax = Syntax(
335
+ json.dumps(data, indent=2),
336
+ "json",
337
+ theme="monokai",
338
+ word_wrap=True
339
+ )
340
+ console.print(syntax)
341
+
342
+ @staticmethod
343
+ def _visualize_list(data: List, context: Optional[str]) -> None:
344
+ """Visualize list as table or tree"""
345
+ if not data:
346
+ console.print(" → (empty)", style="dim")
347
+ return
348
+
349
+ # If list of dicts, create table
350
+ if all(isinstance(item, dict) for item in data):
351
+ # Get all unique keys
352
+ keys = set()
353
+ for item in data:
354
+ keys.update(item.keys())
355
+ keys = sorted(keys)
356
+
357
+ table = Table(
358
+ box=box.ROUNDED,
359
+ show_header=True,
360
+ header_style="bold magenta"
361
+ )
362
+
363
+ for key in keys:
364
+ table.add_column(str(key), style="cyan")
365
+
366
+ for item in data:
367
+ table.add_row(*[str(item.get(key, "")) for key in keys])
368
+
369
+ console.print(table)
370
+
371
+ # If list of strings, show as tree
372
+ elif all(isinstance(item, str) for item in data):
373
+ tree = Tree("📋 Items", guide_style="dim")
374
+ for item in data:
375
+ tree.add(f"• [cyan]{item}[/cyan]")
376
+ console.print(tree)
377
+
378
+ # Otherwise, show as formatted list
379
+ else:
380
+ for i, item in enumerate(data, 1):
381
+ console.print(f" {i}. {item}", style="cyan")