"""Runtime UTF-8 guard for Korean-heavy KCSC tools. Windows shells and MCP stdio clients can disagree about stream encodings. The project stores and exchanges Korean standards text, so every entrypoint should pin process streams to UTF-8 before logging, JSON-RPC, or CLI output starts. """ from __future__ import annotations import os import sys from typing import TextIO UTF8 = "utf-8" def _set_windows_console_utf8() -> None: """Best-effort console codepage switch for interactive Windows runs.""" if os.name != "nt": return try: import ctypes kernel32 = ctypes.windll.kernel32 kernel32.SetConsoleCP(65001) kernel32.SetConsoleOutputCP(65001) except Exception: # Headless MCP/CI processes often have no real console. Stream # reconfiguration below is the part that matters for those cases. return def _reconfigure_stream(stream: TextIO | None, *, errors: str) -> bool: if stream is None: return False reconfigure = getattr(stream, "reconfigure", None) if not callable(reconfigure): return False try: reconfigure(encoding=UTF8, errors=errors) return True except (TypeError, ValueError, OSError): try: reconfigure(errors=errors) return True except (TypeError, ValueError, OSError): return False def configure_utf8_stdio() -> dict[str, str | bool | None]: """Force Korean-safe UTF-8 stdio for CLI, MCP stdio, and REST entrypoints. Returns a small state dictionary for tests and diagnostics. Environment variables are set for child Python processes; current streams are reconfigured directly because PYTHONUTF8/PYTHONIOENCODING are normally read only at interpreter startup. """ os.environ.setdefault("PYTHONUTF8", "1") os.environ.setdefault("PYTHONIOENCODING", UTF8) _set_windows_console_utf8() stdin_ok = _reconfigure_stream(sys.stdin, errors="strict") stdout_ok = _reconfigure_stream(sys.stdout, errors="replace") stderr_ok = _reconfigure_stream(sys.stderr, errors="replace") return { "stdin_encoding": getattr(sys.stdin, "encoding", None), "stdout_encoding": getattr(sys.stdout, "encoding", None), "stderr_encoding": getattr(sys.stderr, "encoding", None), "stdin_reconfigured": stdin_ok, "stdout_reconfigured": stdout_ok, "stderr_reconfigured": stderr_ok, "PYTHONUTF8": os.environ.get("PYTHONUTF8"), "PYTHONIOENCODING": os.environ.get("PYTHONIOENCODING"), }