#!/usr/bin/env python3 """ EU-Utility Platform Detection Utility ====================================== Detects platform capabilities and available features. Can be run standalone to check system compatibility. Usage: python platform_detector.py python platform_detector.py --json python platform_detector.py --markdown """ import sys import os import platform import subprocess import json from typing import Dict, Any, List from dataclasses import dataclass, asdict @dataclass class PlatformCapabilities: """Container for platform capabilities.""" platform: str system: str release: str version: str machine: str processor: str python_version: str # Feature availability has_window_manager: bool has_native_hotkeys: bool has_global_hotkeys: bool has_fcntl: bool has_portalocker: bool has_requests: bool has_paho_mqtt: bool has_easyocr: bool has_pytesseract: bool has_paddleocr: bool has_psutil: bool has_aiohttp: bool has_websockets: bool # System capabilities supports_long_paths: bool supports_unicode_paths: bool has_wsl: bool class PlatformDetector: """Detects platform capabilities.""" def __init__(self): self.is_windows = sys.platform == 'win32' self.is_linux = sys.platform == 'linux' self.is_mac = sys.platform == 'darwin' def detect(self) -> PlatformCapabilities: """Detect all platform capabilities.""" return PlatformCapabilities( platform=platform.platform(), system=platform.system(), release=platform.release(), version=platform.version(), machine=platform.machine(), processor=platform.processor() or 'Unknown', python_version=platform.python_version(), has_window_manager=self._check_window_manager(), has_native_hotkeys=self._check_native_hotkeys(), has_global_hotkeys=self._check_global_hotkeys(), has_fcntl=self._check_module('fcntl'), has_portalocker=self._check_module('portalocker'), has_requests=self._check_module('requests'), has_paho_mqtt=self._check_module('paho.mqtt.client'), has_easyocr=self._check_module('easyocr'), has_pytesseract=self._check_module('pytesseract'), has_paddleocr=self._check_module('paddleocr'), has_psutil=self._check_module('psutil'), has_aiohttp=self._check_module('aiohttp'), has_websockets=self._check_module('websockets'), supports_long_paths=self._check_long_paths(), supports_unicode_paths=self._check_unicode_paths(), has_wsl=self._check_wsl(), ) def _check_module(self, name: str) -> bool: """Check if a module is available.""" try: __import__(name) return True except ImportError: return False def _check_window_manager(self) -> bool: """Check if window manager features are available.""" if self.is_windows: try: import ctypes return True except ImportError: return False elif self.is_linux: # Check for X11 or Wayland return 'DISPLAY' in os.environ or 'WAYLAND_DISPLAY' in os.environ elif self.is_mac: # Limited window manager support on Mac return False return False def _check_native_hotkeys(self) -> bool: """Check if native hotkeys are available.""" if self.is_windows: try: import ctypes return True except ImportError: return False elif self.is_linux: # Check for xbindkeys or similar return subprocess.run(['which', 'xbindkeys'], capture_output=True).returncode == 0 return False def _check_global_hotkeys(self) -> bool: """Check if global hotkeys are available.""" # PyQt6 global hotkeys work on all platforms return True def _check_long_paths(self) -> bool: """Check if long paths are supported.""" if self.is_windows: # Windows 10 1607+ supports long paths try: version = tuple(map(int, platform.version().split('.'))) return version >= (10, 0, 14393) except: return False return True # Linux/Mac always support long paths def _check_unicode_paths(self) -> bool: """Check if Unicode paths are supported.""" import tempfile from pathlib import Path try: test_path = Path(tempfile.gettempdir()) / "测试_unicode_šŸŽ®" test_path.mkdir(exist_ok=True) test_path.rmdir() return True except: return False def _check_wsl(self) -> bool: """Check if running in WSL.""" if self.is_linux: try: with open('/proc/version', 'r') as f: return 'microsoft' in f.read().lower() except: pass return False def print_report(self, caps: PlatformCapabilities): """Print human-readable report.""" print("=" * 60) print("EU-Utility Platform Detection Report") print("=" * 60) print("\nšŸ“‹ Platform Information:") print(f" System: {caps.system}") print(f" Release: {caps.release}") print(f" Version: {caps.version}") print(f" Machine: {caps.machine}") print(f" Processor: {caps.processor}") print(f" Python: {caps.python_version}") if caps.has_wsl: print(" āš ļø Running in WSL") print("\nšŸ”§ Core Features:") print(f" Window Manager: {'āœ…' if caps.has_window_manager else 'āŒ'}") print(f" Native Hotkeys: {'āœ…' if caps.has_native_hotkeys else 'āŒ'}") print(f" Global Hotkeys: {'āœ…' if caps.has_global_hotkeys else 'āŒ'}") print("\nšŸ”’ File Locking:") print(f" fcntl: {'āœ…' if caps.has_fcntl else 'āŒ'}") print(f" portalocker: {'āœ…' if caps.has_portalocker else 'āŒ'}") print("\n🌐 Network & Communication:") print(f" requests: {'āœ…' if caps.has_requests else 'āŒ'}") print(f" paho-mqtt: {'āœ…' if caps.has_paho_mqtt else 'āŒ'}") print(f" aiohttp: {'āœ…' if caps.has_aiohttp else 'āŒ'}") print(f" websockets: {'āœ…' if caps.has_websockets else 'āŒ'}") print("\nšŸ“· OCR Engines:") print(f" EasyOCR: {'āœ…' if caps.has_easyocr else 'āŒ'}") print(f" Tesseract: {'āœ…' if caps.has_pytesseract else 'āŒ'}") print(f" PaddleOCR: {'āœ…' if caps.has_paddleocr else 'āŒ'}") print("\nšŸ› ļø Utilities:") print(f" psutil: {'āœ…' if caps.has_psutil else 'āŒ'}") print("\nšŸ“ Path Support:") print(f" Long Paths: {'āœ…' if caps.supports_long_paths else 'āŒ'}") print(f" Unicode Paths: {'āœ…' if caps.supports_unicode_paths else 'āŒ'}") # Recommendations print("\nšŸ’” Recommendations:") recommendations = self._get_recommendations(caps) if recommendations: for rec in recommendations: print(f" • {rec}") else: print(" All core dependencies satisfied!") print("\n" + "=" * 60) def _get_recommendations(self, caps: PlatformCapabilities) -> List[str]: """Get installation recommendations.""" recs = [] if not caps.has_requests: recs.append("Install requests: pip install requests") if not caps.has_psutil: recs.append("Install psutil for system info: pip install psutil") if not any([caps.has_easyocr, caps.has_pytesseract, caps.has_paddleocr]): recs.append("Install an OCR engine: pip install easyocr (or pytesseract, paddleocr)") if self.is_windows and not caps.has_portalocker: recs.append("Install portalocker for file locking: pip install portalocker") if not caps.has_aiohttp: recs.append("Install aiohttp for async HTTP: pip install aiohttp") return recs def print_json(self, caps: PlatformCapabilities): """Print JSON report.""" print(json.dumps(asdict(caps), indent=2)) def print_markdown(self, caps: PlatformCapabilities): """Print Markdown report.""" print("# EU-Utility Platform Report") print() print("## Platform Information") print() print(f"| Property | Value |") print(f"|----------|-------|") print(f"| System | {caps.system} |") print(f"| Release | {caps.release} |") print(f"| Version | {caps.version} |") print(f"| Machine | {caps.machine} |") print(f"| Processor | {caps.processor} |") print(f"| Python | {caps.python_version} |") print() print("## Feature Support") print() print(f"| Feature | Status |") print(f"|---------|--------|") print(f"| Window Manager | {'āœ…' if caps.has_window_manager else 'āŒ'} |") print(f"| Native Hotkeys | {'āœ…' if caps.has_native_hotkeys else 'āŒ'} |") print(f"| Global Hotkeys | {'āœ…' if caps.has_global_hotkeys else 'āŒ'} |") print(f"| File Locking | {'āœ…' if (caps.has_fcntl or caps.has_portalocker) else 'āŒ'} |") print(f"| Network (requests) | {'āœ…' if caps.has_requests else 'āŒ'} |") print(f"| MQTT | {'āœ…' if caps.has_paho_mqtt else 'āŒ'} |") print(f"| OCR | {'āœ…' if any([caps.has_easyocr, caps.has_pytesseract, caps.has_paddleocr]) else 'āŒ'} |") print() def main(): import argparse parser = argparse.ArgumentParser(description="EU-Utility Platform Detector") parser.add_argument("--json", action="store_true", help="Output JSON format") parser.add_argument("--markdown", action="store_true", help="Output Markdown format") args = parser.parse_args() detector = PlatformDetector() caps = detector.detect() if args.json: detector.print_json(caps) elif args.markdown: detector.print_markdown(caps) else: detector.print_report(caps) if __name__ == "__main__": main()