diff --git a/shared_utils.py b/shared_utils.py index 54ef3d3..afe4cb8 100644 --- a/shared_utils.py +++ b/shared_utils.py @@ -4,20 +4,62 @@ from __future__ import annotations import json from pathlib import Path from typing import Any, Dict, List, Optional, Sequence, Tuple -from typing import Dict, List, Optional, Sequence, Tuple import numpy as np import pandas as pd import pyodbc -DEFAULT_CONFIG_PATH = Path("config/pattern_knn_config.json") +CONFIG_FILENAME = "pattern_knn_config.json" + +# Ordine di ricerca del file di configurazione. Il primo trovato vince. +# Tutti i path sono relativi al CWD eccetto quello accanto a shared_utils.py. +_CONFIG_SEARCH_PATHS = [ + Path(CONFIG_FILENAME), # root del progetto + Path("config") / CONFIG_FILENAME, # sottocartella config/ + Path(__file__).resolve().parent / CONFIG_FILENAME, # stessa cartella di shared_utils.py + Path(__file__).resolve().parent / "config" / CONFIG_FILENAME, +] + +# Backward-compat: alcuni script importano DEFAULT_CONFIG_PATH direttamente. +DEFAULT_CONFIG_PATH = _CONFIG_SEARCH_PATHS[0] + + +def _resolve_config_path(explicit: Optional[Path] = None) -> Path: + """Restituisce il path al file di config, cercando in piu' posizioni standard. + + Priorita': + 1. Argomento esplicito passato a load_config() + 2. Variabile ambiente PATTERN_KNN_CONFIG_PATH + 3. Lista _CONFIG_SEARCH_PATHS in ordine + """ + import os + + if explicit is not None: + return Path(explicit) + + env_path = os.environ.get("PATTERN_KNN_CONFIG_PATH") + if env_path: + return Path(env_path) + + for candidate in _CONFIG_SEARCH_PATHS: + if candidate.exists(): + return candidate + + # Nessuna posizione standard trovata: ritorna la prima per generare un + # messaggio di errore informativo a valle. + return _CONFIG_SEARCH_PATHS[0] def load_config(path: Optional[Path] = None) -> Dict: """Load the JSON configuration that holds operational parameters.""" - cfg_path = Path(path or DEFAULT_CONFIG_PATH) + cfg_path = _resolve_config_path(path) if not cfg_path.exists(): - raise FileNotFoundError(f"Missing configuration file: {cfg_path}") + searched = "\n - ".join(str(p.resolve()) for p in _CONFIG_SEARCH_PATHS) + raise FileNotFoundError( + f"Missing configuration file '{CONFIG_FILENAME}'.\n" + f"Searched in:\n - {searched}\n" + f"Set PATTERN_KNN_CONFIG_PATH env var to override." + ) with cfg_path.open("r", encoding="utf-8") as fh: return json.load(fh) @@ -96,7 +138,7 @@ def build_pattern_library( """Create the normalized pattern windows and their realized outcomes. Args: - ret_series: Series of returns (ordered oldest→latest). + ret_series: Series of returns (ordered oldest->latest). wp: Window length for the pattern. ha: Holding horizon used to compute the outcome. embargo: Optional number of most-recent observations to exclude when