Files
MajoorWaldi-ComfyUI-Majoor-…/mjr_am_backend/utils.py
T
Ewald a2053d0cba refactor(v2): plan V2 complet — splits JS, tests frontend, durcissement securite
Chantier F - Typage Python
- ruff S101 déplacé en per-file-ignores (pyproject.toml)
- pyrightconfig.json : mode standard confirmé

Chantier G - Assertions & bare-except
- 16 blocs except documentés dans config.py
- --cov-branch activé, seuil coverage 60→68%

Chantier H - Cache settings
- Stratégie documentée dans settings.py
- _resolve_index_dir() logguée dans config.py

Chantier I - Split gros fichiers JS
- client.js 1509L → client.js 406L + clientAuth.js + clientOps.js + fetchUtils.js
- toolbar.js 927L → toolbar.js 458L + toolbarActions.js + toolbarControls.js
- FloatingViewer.js → FloatingViewer.impl.js + floatingViewer*(8 modules)
- Viewer_impl.js → ViewerRuntime.js + viewerShell.js + viewerThemeStyles.js + viewerOverlayDismiss.js
- model3dRenderer.js → model3dRenderer.impl.js + model3dCore.js + model3dLoaders.js + model3dSupport.js
- dialogs.js → dialogs.js + DialogTemplates.js

Chantier J - Tests frontend (Phases 1-2)
- use_drag_drop.vitest.mjs : 5 tests
- use_grid_state.vitest.mjs : 18 tests
- security_client_headers, security_deep_merge, security_runtime_state, runtime_store, dialog_templates
- Total: 80 fichiers test / 350 tests vitest

Chantier K - Pinia migration
- runtimeState.js entièrement migré vers Pinia
- getOptionalRuntimeStore.js + runtimeEnrichmentState.js ajoutés

Chantier L - Durcissement sécurité
- tests/security/test_rate_limit.py : 8 tests rate-limit (state machine complète)
- clientAuth.js : docstring sessionStorage security boundary
- three.js 0.183.2 audité : 0 CVE (Snyk)

Chantier M - Simplification config
- deps.py, tool_detect.py, utils.py nettoyés

docs: PLAN_REFACTO_V2_LONG_TERME.md ajouté et clôturé
.gitignore: coverage/ ajouté
2026-04-11 09:38:41 +02:00

81 lines
2.3 KiB
Python

"""
Utility helpers shared across backend modules.
"""
from __future__ import annotations
import math
import os
from typing import Any
from .shared import get_logger
BOOL_TRUE_VALUES = frozenset({"1", "true", "yes", "on", "enabled"})
BOOL_FALSE_VALUES = frozenset({"0", "false", "no", "off", "disabled"})
logger = get_logger(__name__)
def parse_bool(value: Any, default: bool = False) -> bool:
if isinstance(value, bool):
return value
if isinstance(value, (int, float)):
return bool(value)
if isinstance(value, str):
normalized = value.strip().lower()
if normalized in BOOL_TRUE_VALUES:
return True
if normalized in BOOL_FALSE_VALUES:
return False
try:
return bool(float(normalized))
except (ValueError, TypeError, OverflowError):
logger.debug("parse_bool could not coerce %r via float fallback", value)
pass
return default
def env_bool(name: str, default: bool) -> bool:
if not name:
return default
try:
raw = os.environ.get(name)
except Exception:
raw = None
if raw is None:
return default
return parse_bool(raw, default)
def env_float(name: str, default: float) -> float:
if not name:
return default
try:
raw = os.environ.get(name)
except Exception:
raw = None
if raw is None:
return default
try:
return float(raw)
except (ValueError, TypeError):
return default
def sanitize_for_json(obj: Any) -> Any:
"""Recursively replace NaN/Infinity float values with ``None`` so the
result is valid JSON. ComfyUI nodes routinely store ``float('nan')`` in
``is_changed`` to signal *always re-execute*; Python's ``json.dumps``
emits that as the bare token ``NaN`` which browsers reject.
"""
if isinstance(obj, float):
return None if (math.isnan(obj) or math.isinf(obj)) else obj
if isinstance(obj, bytes):
try:
return obj.decode("utf-8")
except (UnicodeDecodeError, ValueError):
return obj.hex()
if isinstance(obj, dict):
return {k: sanitize_for_json(v) for k, v in obj.items()}
if isinstance(obj, list):
return [sanitize_for_json(v) for v in obj]
return obj