127 lines
3.3 KiB
Python
127 lines
3.3 KiB
Python
#!/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
|