kcsc-mcp / src /runtime_encoding.py
nicefree19's picture
Upload 105 files
0ee3c92 verified
Raw
History Blame Contribute Delete
2.58 kB
"""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"),
}