275 lines
9.4 KiB
Python
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() |