#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Runtime Compatibility Module Provides cross-platform compatibility utilities for Noma. """ import sys import os from pathlib import Path def enable_windows_utf8_stdio(skip_in_pytest: bool = False): """ Enable UTF-8 mode for Windows stdout/stderr. On Windows, the console defaults to the system code page encoding, which doesn't support UTF-8 well. This function attempts to configure the console for UTF-8 operation. Args: skip_in_pytest: If True, skip UTF-8 configuration when running in pytest. This prevents interference with pytest's output capture. """ if sys.platform != "win32": return # Skip if running in pytest if skip_in_pytest and "pytest" in sys.modules: return try: # Windows-specific setup for UTF-8 import ctypes import io # Try to set console mode to enable UTF-8 kernel32 = ctypes.windll.kernel32 # Get stdout handle stdout_handle = kernel32.GetStdHandle(-11) # STD_OUTPUT_HANDLE stderr_handle = kernel32.GetStdHandle(-12) # STD_ERROR_HANDLE # Enable UTF-8 mode by setting code page kernel32.SetConsoleOutputCP(65001) # UTF-8 code page kernel32.SetConsoleCP(65001) # Reconfigure stdout/stderr as UTF-8 text streams if sys.stdout.encoding != 'utf-8': sys.stdout = io.TextIOWrapper( sys.stdout.buffer, encoding='utf-8', errors='replace' ) if sys.stderr.encoding != 'utf-8': sys.stderr = io.TextIOWrapper( sys.stderr.buffer, encoding='utf-8', errors='replace' ) # 设置环境变量,确保 Python 使用 UTF-8 os.environ.setdefault('PYTHONIOENCODING', 'utf-8') except Exception as e: # 记录警告但不中断程序 import logging logger = logging.getLogger(__name__) logger.warning(f"Failed to enable Windows UTF-8 mode: {e}") def normalize_windows_path(path: str) -> Path: """ Normalize a path for Windows compatibility. Converts forward slashes to backslashes and resolves environment variables. Args: path: Path string to normalize (can also be a Path object) Returns: Normalized Path object """ if isinstance(path, Path): return path path_str = str(path) if sys.platform != "win32": return Path(path_str) # Convert forward slashes to backslashes path_str = path_str.replace('/', '\\') # Expand environment variables path_str = os.path.expandvars(path_str) # Return as Path object return Path(path_str) def get_system_encoding() -> str: """Get the system encoding.""" if sys.platform == "win32": import ctypes kernel32 = ctypes.windll.kernel32 return f"cp{kernel32.GetConsoleCP()}" return sys.getdefaultencoding() def ensure_directory_exists(path: str) -> bool: """ Ensure a directory exists, creating it if necessary. Args: path: Directory path Returns: True if directory exists or was created successfully """ try: os.makedirs(path, exist_ok=True) return True except Exception: return False