#!/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()