Files
StreamLens/setup_textual_debugging.py

275 lines
9.4 KiB
Python

#!/usr/bin/env python3
"""
Setup script to integrate Textual debugging tools with StreamLens
"""
import sys
from pathlib import Path
def setup_debugging_integration():
"""Add debugging capabilities to StreamLens app"""
app_path = Path("analyzer/tui/textual/app_v2.py")
if not app_path.exists():
print("❌ StreamLens app file not found")
return False
# Read current app file
with open(app_path, 'r') as f:
content = f.read()
# Check if debugging is already integrated
if "TextualStateMonitor" in content:
print("✅ Debugging already integrated")
return True
# Add debugging imports
import_addition = '''
# Debugging imports
try:
from textual_state_visualizer import TextualStateMonitor, TextualStateWebServer
from textual_inspector import inspect_textual_app, print_widget_tree
DEBUGGING_AVAILABLE = True
except ImportError:
DEBUGGING_AVAILABLE = False
'''
# Find the right place to add imports (after existing imports)
lines = content.split('\n')
import_index = 0
for i, line in enumerate(lines):
if line.startswith('if TYPE_CHECKING:'):
import_index = i
break
else:
# Find last import line
for i, line in enumerate(lines):
if line.startswith('from ') or line.startswith('import '):
import_index = i + 1
# Insert debugging imports
lines.insert(import_index, import_addition)
# Add debugging methods to the app class
debugging_methods = '''
# Debugging methods
def start_debugging(self, web_interface: bool = True, port: int = 8080):
"""Start debugging tools"""
if not DEBUGGING_AVAILABLE:
print("❌ Debugging tools not available. Run: pip install watchdog")
return
self._debug_monitor = TextualStateMonitor(self)
self._debug_monitor.start_monitoring()
if web_interface:
self._debug_server = TextualStateWebServer(self._debug_monitor, port)
self._debug_server.start()
print(f"🔍 Debug monitoring started!")
if web_interface:
print(f"🌐 Web interface: http://localhost:{port}")
def stop_debugging(self):
"""Stop debugging tools"""
if hasattr(self, '_debug_monitor') and self._debug_monitor:
self._debug_monitor.stop_monitoring()
if hasattr(self, '_debug_server') and self._debug_server:
self._debug_server.stop()
def debug_widget_tree(self):
"""Print current widget tree to console"""
if not DEBUGGING_AVAILABLE:
print("❌ Debugging tools not available")
return
data = inspect_textual_app(self)
print("🔍 TEXTUAL APP INSPECTION")
print("=" * 50)
print_widget_tree(data.get('current_screen', {}))
def debug_focused_widget(self):
"""Print info about currently focused widget"""
focused = self.focused
if focused:
print(f"🎯 Focused widget: {focused.__class__.__name__}")
if hasattr(focused, 'id'):
print(f" ID: {focused.id}")
if hasattr(focused, 'classes'):
print(f" Classes: {list(focused.classes)}")
if hasattr(focused, 'label'):
print(f" Label: {focused.label}")
else:
print("🎯 No widget has focus")
# Debugging key bindings
def action_debug_tree(self):
"""Debug action: Print widget tree"""
self.debug_widget_tree()
def action_debug_focus(self):
"""Debug action: Print focused widget"""
self.debug_focused_widget()
def action_start_web_debug(self):
"""Debug action: Start web debugging interface"""
self.start_debugging()
'''
# Find the class definition and add methods
class_found = False
for i, line in enumerate(lines):
if line.strip().startswith('class StreamLensAppV2'):
class_found = True
# Find the end of the class to add methods
indent_level = len(line) - len(line.lstrip())
# Find a good place to insert methods (before the last method or at the end)
insert_index = len(lines)
for j in range(i + 1, len(lines)):
if lines[j].strip() and not lines[j].startswith(' ' * (indent_level + 1)):
insert_index = j
break
# Insert debugging methods
method_lines = debugging_methods.split('\n')
for k, method_line in enumerate(method_lines):
lines.insert(insert_index + k, method_line)
break
if not class_found:
print("❌ StreamLensAppV2 class not found")
return False
# Add debugging key bindings to BINDINGS
for i, line in enumerate(lines):
if 'BINDINGS = [' in line:
# Find the end of BINDINGS
bracket_count = 0
for j in range(i, len(lines)):
bracket_count += lines[j].count('[') - lines[j].count(']')
if bracket_count == 0:
# Insert debugging bindings before the closing bracket
debug_bindings = [
' Binding("ctrl+d,t", "debug_tree", "Debug: Widget Tree", show=False),',
' Binding("ctrl+d,f", "debug_focus", "Debug: Focused Widget", show=False),',
' Binding("ctrl+d,w", "start_web_debug", "Debug: Web Interface", show=False),'
]
for k, binding in enumerate(debug_bindings):
lines.insert(j + k, binding)
break
break
# Write the modified content
new_content = '\n'.join(lines)
# Create backup
backup_path = app_path.with_suffix('.py.backup')
with open(backup_path, 'w') as f:
f.write(content)
print(f"📁 Backup created: {backup_path}")
# Write modified file
with open(app_path, 'w') as f:
f.write(new_content)
print("✅ Debugging integration added to StreamLens app")
print("\nNew debugging features:")
print(" 🔧 self.start_debugging() - Start debug monitoring with web interface")
print(" 🔍 self.debug_widget_tree() - Print widget tree to console")
print(" 🎯 self.debug_focused_widget() - Print focused widget info")
print(" ⌨️ Ctrl+D,T - Debug widget tree")
print(" ⌨️ Ctrl+D,F - Debug focused widget")
print(" ⌨️ Ctrl+D,W - Start web debug interface")
return True
def install_dependencies():
"""Install required dependencies"""
import subprocess
print("📦 Installing debugging dependencies...")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "watchdog"])
print("✅ Dependencies installed")
return True
except subprocess.CalledProcessError:
print("❌ Failed to install dependencies")
print("Please run: pip install watchdog")
return False
def create_development_script():
"""Create a development script for easy debugging"""
dev_script = '''#!/usr/bin/env python3
"""
StreamLens Development Script with Debugging
"""
import sys
from pathlib import Path
# Add analyzer to path
sys.path.insert(0, str(Path(__file__).parent))
from analyzer.tui.textual.app_v2 import StreamLensAppV2
def main():
"""Run StreamLens with debugging enabled"""
print("🚀 Starting StreamLens in debug mode...")
app = StreamLensAppV2()
# Start debugging automatically
app.start_debugging(web_interface=True, port=8080)
# Run the app
app.run()
if __name__ == "__main__":
main()
'''
with open("debug_streamlens.py", 'w') as f:
f.write(dev_script)
print("✅ Created debug_streamlens.py - Run with: python debug_streamlens.py")
def main():
print("🔧 StreamLens Textual Debugging Setup")
print("=" * 50)
# Install dependencies
if not install_dependencies():
return
# Setup debugging integration
if not setup_debugging_integration():
return
# Create development script
create_development_script()
print("\n🎉 Setup complete! Here's how to use the debugging tools:")
print("\n1. **Development Mode**: python debug_streamlens.py")
print(" - Starts app with web debugging interface automatically")
print(" - Opens browser to http://localhost:8080")
print("\n2. **Live Reload**: python textual_dev_server.py debug_streamlens.py")
print(" - Restarts app when you modify Python files")
print("\n3. **Manual Debugging**: In your app, call:")
print(" - app.debug_widget_tree() - Print widget hierarchy")
print(" - app.debug_focused_widget() - Check what has focus")
print(" - app.start_debugging() - Start web interface")
print("\n4. **Keyboard Shortcuts** (while app is running):")
print(" - Ctrl+D,T - Print widget tree")
print(" - Ctrl+D,F - Print focused widget")
print(" - Ctrl+D,W - Start web debug interface")
print("\n5. **Testing**: python textual_test_framework.py")
print(" - Run automated tests on your Textual components")
if __name__ == "__main__":
main()