Let a decode failure degrade instead of escaping a fail-closed helper (#7487)
* Let a decode failure degrade instead of escaping a fail-closed helper Pinning utf-8 makes a read that used to return mojibake on Windows raise instead. 33 of those reads sit under a handler catching OSError or json.JSONDecodeError but not UnicodeDecodeError, which subclasses ValueError, so a corrupt file would now escape a helper written to return a default. Adds UnicodeDecodeError to those tuples only. * Treat an undecodable install lock as stale instead of retrying forever
This commit is contained in:
parent
3fd948eb95
commit
1daaa5cbb4
17 changed files with 37 additions and 33 deletions
|
|
@ -109,7 +109,7 @@ def _load_colab_login_credentials() -> "tuple[str, str] | None":
|
|||
lines = path.read_text(encoding = "utf-8").splitlines()
|
||||
if len(lines) >= 2 and lines[0] and lines[1]:
|
||||
return lines[0], lines[1]
|
||||
except OSError as e:
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
logger.info(f"Could not load Colab login credentials ({e}).")
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ def _wsl_system_rocm_lib_dirs() -> "list[str]":
|
|||
with open("/proc/version", encoding = "utf-8", errors = "replace") as fh:
|
||||
if "microsoft" not in fh.read().lower():
|
||||
return []
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return []
|
||||
out: "list[str]" = []
|
||||
for d in ("/opt/rocm/lib", "/opt/rocm/lib64"):
|
||||
|
|
@ -573,7 +573,7 @@ def _load_swa_cache() -> dict:
|
|||
_SWA_CACHE = json.load(f)
|
||||
if not isinstance(_SWA_CACHE, dict):
|
||||
_SWA_CACHE = {}
|
||||
except (FileNotFoundError, json.JSONDecodeError, OSError):
|
||||
except (FileNotFoundError, json.JSONDecodeError, OSError, UnicodeDecodeError):
|
||||
_SWA_CACHE = {}
|
||||
return _SWA_CACHE
|
||||
|
||||
|
|
@ -586,7 +586,7 @@ def _save_swa_cache(cache: dict) -> None:
|
|||
with open(tmp, "w", encoding = "utf-8") as f:
|
||||
json.dump(cache, f, indent = 2, sort_keys = True)
|
||||
tmp.replace(path)
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -5138,7 +5138,7 @@ class LlamaCppBackend:
|
|||
self._llama_log_path = log_dir / f"diffusion-{int(time.time())}-port-{self._port}.log"
|
||||
self._llama_log_fh = open(self._llama_log_path, "w", encoding = "utf-8", buffering = 1)
|
||||
logger.info(f"diffusion runner stdout/stderr -> {self._llama_log_path}")
|
||||
except OSError as e:
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
logger.debug(f"Could not open diffusion runner log file: {e}")
|
||||
|
||||
# The shim (and its visual server) die with this backend process, so a
|
||||
|
|
@ -6355,7 +6355,7 @@ class LlamaCppBackend:
|
|||
buffering = 1,
|
||||
)
|
||||
logger.info(f"llama-server stdout/stderr -> {self._llama_log_path}")
|
||||
except OSError as e:
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
# Best-effort; never block the load on logging.
|
||||
logger.debug(f"Could not open llama-server log file: {e}")
|
||||
self._llama_log_path = None
|
||||
|
|
@ -8302,7 +8302,7 @@ class LlamaCppBackend:
|
|||
buffering = 1,
|
||||
)
|
||||
logger.info(f"llama-server stdout/stderr -> {self._llama_log_path}")
|
||||
except OSError as e:
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
# Best-effort; never block the load on logging.
|
||||
logger.debug(f"Could not open llama-server log file: {e}")
|
||||
self._llama_log_path = None
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ def _ollama_model_info_from_manifest(
|
|||
|
||||
try:
|
||||
manifest = json.loads(tag_file.read_text(encoding = "utf-8"))
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError) as e:
|
||||
logger.debug("Skipping unreadable/invalid Ollama manifest %s: %s", tag_file, e)
|
||||
return None
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ def _ollama_model_info_from_manifest(
|
|||
cfg = json.loads(config_blob.read_text(encoding = "utf-8"))
|
||||
model_type = cfg.get("model_type", "")
|
||||
file_type = cfg.get("file_type", "")
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError) as e:
|
||||
logger.debug("Could not parse Ollama config blob %s: %s", config_blob, e)
|
||||
|
||||
layers = manifest.get("layers") or []
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ def _read_marker_value(marker: Path) -> Optional[str]:
|
|||
if not marker.exists():
|
||||
return None
|
||||
value = marker.read_text(encoding = "utf-8").strip()
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return None
|
||||
return value if value in VALID_TRANSPORTS else None
|
||||
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ def get_unsloth_version() -> str:
|
|||
for line in version_file.read_text(encoding = "utf-8").splitlines():
|
||||
if line.startswith("__version__ = "):
|
||||
return line.split("=", 1)[1].strip().strip('"').strip("'")
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
pass
|
||||
return "dev"
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class UnstructuredSeedReader(SeedReader[UnstructuredSeedSource]):
|
|||
try:
|
||||
meta = json_mod.loads(meta_path.read_text(encoding = "utf-8"))
|
||||
orig_name = meta.get("original_filename", path_obj.name)
|
||||
except (json_mod.JSONDecodeError, OSError):
|
||||
except (json_mod.JSONDecodeError, OSError, UnicodeDecodeError):
|
||||
pass
|
||||
file_entries.append((path_obj, orig_name))
|
||||
|
||||
|
|
|
|||
|
|
@ -723,7 +723,7 @@ def _scan_ollama_dir(ollama_dir: Path, limit: Optional[int] = None) -> List[Loca
|
|||
|
||||
try:
|
||||
manifest = json.loads(tag_file.read_text(encoding = "utf-8"))
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError) as e:
|
||||
logger.debug(
|
||||
"Skipping unreadable/invalid Ollama manifest %s: %s",
|
||||
tag_file,
|
||||
|
|
@ -741,7 +741,7 @@ def _scan_ollama_dir(ollama_dir: Path, limit: Optional[int] = None) -> List[Loca
|
|||
cfg = json.loads(config_blob.read_text(encoding = "utf-8"))
|
||||
model_type = cfg.get("model_type", "")
|
||||
file_type = cfg.get("file_type", "")
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError) as e:
|
||||
logger.debug(
|
||||
"Could not parse Ollama config blob %s: %s",
|
||||
config_blob,
|
||||
|
|
|
|||
|
|
@ -786,7 +786,7 @@ def _remove_pid_file():
|
|||
stored = _PID_FILE.read_text(encoding = "utf-8").strip()
|
||||
if stored == str(os.getpid()):
|
||||
_PID_FILE.unlink(missing_ok = True)
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -934,7 +934,7 @@ def _iter_frontend_fallback_candidates() -> "list[Path]":
|
|||
for finder in sp.glob("__editable___*_finder.py"):
|
||||
try:
|
||||
src = finder.read_text(encoding = "utf-8")
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
# Tolerate single/multi-line dict literals; [^}]* rejects nested
|
||||
# dicts, which the setuptools editable template never emits.
|
||||
|
|
|
|||
|
|
@ -903,7 +903,7 @@ def _rocm_kfd_gpu_pci_ids() -> list[str]:
|
|||
props[parts[0]] = int(parts[1])
|
||||
except ValueError:
|
||||
continue
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return [] # unreadable node could be a GPU: fail closed, don't shift
|
||||
if props.get("simd_count", 0) <= 0:
|
||||
continue # CPU node, not a GPU
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ def _xdg_user_dir(key: str) -> Path | None:
|
|||
config = Path.home() / ".config" / "user-dirs.dirs"
|
||||
try:
|
||||
lines = config.read_text(encoding = "utf-8").splitlines()
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return None
|
||||
prefix = f"{key}="
|
||||
for line in lines:
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ def hf_cache_snapshot_dir(model_name: str) -> Optional[Path]:
|
|||
snapshot = repo_dir / "snapshots" / commit
|
||||
if snapshot.is_dir():
|
||||
return snapshot
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -2508,7 +2508,7 @@ def detect_host() -> HostInfo:
|
|||
if _vf.read().strip().lower() == "0x8086":
|
||||
has_intel_gpu = True
|
||||
break
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
elif is_windows:
|
||||
# Registry first (in-process; see windows_intel_gpu_in_registry).
|
||||
|
|
@ -4264,7 +4264,7 @@ def free_local_port() -> int:
|
|||
def read_log_excerpt(log_path: Path, *, max_lines: int = 60) -> str:
|
||||
try:
|
||||
content = log_path.read_text(encoding = "utf-8", errors = "replace")
|
||||
except FileNotFoundError:
|
||||
except (FileNotFoundError, UnicodeDecodeError):
|
||||
return ""
|
||||
return "\n".join(content.splitlines()[-max_lines:])
|
||||
|
||||
|
|
@ -4680,7 +4680,7 @@ def _wsl_system_rocm_lib_dirs() -> list[str]:
|
|||
with open("/proc/version", encoding = "utf-8", errors = "replace") as fh:
|
||||
if "microsoft" not in fh.read().lower():
|
||||
return []
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return []
|
||||
out: list[str] = []
|
||||
for d in ("/opt/rocm/lib", "/opt/rocm/lib64"):
|
||||
|
|
|
|||
|
|
@ -535,7 +535,9 @@ def install_lock(lock_path: Path) -> Iterator[None]:
|
|||
break
|
||||
except FileExistsError:
|
||||
try:
|
||||
raw = lock_path.read_text(encoding = "utf-8").strip()
|
||||
# errors="replace" so an undecodable lock reaches the int()
|
||||
# below and is treated as a stale PID, not retried forever.
|
||||
raw = lock_path.read_text(encoding = "utf-8", errors = "replace").strip()
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
stale = False
|
||||
|
|
@ -669,7 +671,7 @@ def load_metadata(install_dir: Path) -> dict | None:
|
|||
return None
|
||||
try:
|
||||
data = json.loads(path.read_text(encoding = "utf-8"))
|
||||
except (json.JSONDecodeError, OSError):
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError):
|
||||
return None
|
||||
return data if isinstance(data, dict) else None
|
||||
|
||||
|
|
|
|||
|
|
@ -776,7 +776,7 @@ def _linux_amd_gfx_from_cpuinfo() -> "str | None":
|
|||
"""Infer gfx arch from /proc/cpuinfo on integrated AMD APUs (Strix Halo/Point)."""
|
||||
try:
|
||||
text = Path("/proc/cpuinfo").read_text(encoding = "utf-8", errors = "replace")
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return None
|
||||
if re.search(r"Ryzen AI Max|Radeon 80[0-9][05]S|Strix Halo", text, re.IGNORECASE):
|
||||
return "gfx1151"
|
||||
|
|
@ -828,7 +828,7 @@ def _is_wsl() -> bool:
|
|||
try:
|
||||
with open("/proc/version", encoding = "utf-8", errors = "replace") as fh:
|
||||
return "microsoft" in fh.read().lower()
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
return False
|
||||
|
||||
|
||||
|
|
@ -856,7 +856,7 @@ def _linux_amd_display_device_present() -> bool:
|
|||
continue
|
||||
if (dev / "class").read_text(encoding = "utf-8").strip().startswith("0x03"):
|
||||
return True
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
except OSError:
|
||||
pass
|
||||
|
|
@ -1069,7 +1069,7 @@ def _has_rocm_gpu() -> bool:
|
|||
try:
|
||||
with open(gpu_id_path, encoding = "utf-8") as fh:
|
||||
gpu_id = fh.read().strip()
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
if not gpu_id or gpu_id == "0": # gpu_id 0 = CPU node
|
||||
continue
|
||||
|
|
@ -1081,7 +1081,7 @@ def _has_rocm_gpu() -> bool:
|
|||
try:
|
||||
with open(props_path, encoding = "utf-8") as fh:
|
||||
props = fh.read()
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue # can't confirm vendor -- skip
|
||||
if not re.search(r"\bvendor_id\s+4098\b", props):
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,9 @@ def install_lock(lock_path: Path) -> Iterator[None]:
|
|||
except FileExistsError:
|
||||
stale = False
|
||||
try:
|
||||
raw = lock_path.read_text(encoding = "utf-8").strip()
|
||||
# errors="replace" so an undecodable lock reaches the int()
|
||||
# below and is treated as a corrupt PID, not retried forever.
|
||||
raw = lock_path.read_text(encoding = "utf-8", errors = "replace").strip()
|
||||
except FileNotFoundError:
|
||||
# Lock vanished between our open and read -- retry
|
||||
continue
|
||||
|
|
@ -2070,7 +2072,7 @@ def load_prebuilt_metadata(ops: ModuleOps, install_dir: Path) -> dict[str, Any]
|
|||
return None
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding = "utf-8"))
|
||||
except (json.JSONDecodeError, OSError):
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError):
|
||||
return None
|
||||
return payload if isinstance(payload, dict) else None
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ def _json_rank_count_from_env(name: str) -> Optional[int]:
|
|||
else:
|
||||
with open(value, "r", encoding = "utf-8") as f:
|
||||
data = json.load(f)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
except (json.JSONDecodeError, OSError, UnicodeDecodeError):
|
||||
return None
|
||||
if isinstance(data, list):
|
||||
return len(data)
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ def _iter_editable_studio_source_roots(venv_dir: Path):
|
|||
for finder in sp.glob("__editable___*_finder.py"):
|
||||
try:
|
||||
src = finder.read_text(encoding = "utf-8")
|
||||
except OSError:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
# Tolerate single- or multi-line dict literals; [^}]* still
|
||||
# rejects nested dicts, which the setuptools template never
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue