"""Diagnostic: submit the minimal request via datapi directly and capture the EXACT ECDS job document (the 'rejected' reason the cdsapi wrapper hides), plus the dataset constraints (valid request space). Read-only diagnosis; no download. """ import json import os import time import datapi ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ECDS_URL = "https://ecds.ecmwf.int/api" DATASET = "s2s-reforecasts" req = json.load(open(os.path.join(ROOT, "config", "ecds_minimal_request.json"))) req.pop("_comment", None) def _get_key(): k = os.environ.get("CDSAPI_KEY") if k: return k rc = os.environ.get("CDSAPI_RC", os.path.expanduser("~/.cdsapirc")) if os.path.exists(rc): for line in open(rc): if line.strip().startswith("key"): return line.split(":", 1)[1].strip() return None out = {"request": req} c = datapi.ApiClient(url=ECDS_URL, key=_get_key()) # 1) constraints given the fixed selectors (reveals valid values) try: proc = c.get_process(DATASET) con = proc.apply_constraints({ "origin": "ecmwf", "forecast_type": "control_forecast", "level_type": "single_level", }) out["constraints_keys"] = sorted(con.keys()) if isinstance(con, dict) else str(type(con)) out["constraints_sample"] = {k: (con[k][:12] if isinstance(con[k], list) else con[k]) for k in list(con)[:20]} if isinstance(con, dict) else None except Exception as e: out["constraints_error"] = f"{type(e).__name__}: {e}" # 2) submit and capture the raw job document on the terminal state try: remote = c.submit(DATASET, req) out["request_id"] = remote.request_id print("submitted", remote.request_id, flush=True) term = {"successful", "failed", "rejected", "dismissed", "deleted"} st = None for _ in range(120): st = remote.status if st in term: break time.sleep(5) out["final_status"] = st try: out["job_json"] = remote.json except Exception as e: out["job_json_error"] = f"{type(e).__name__}: {e}" except Exception as e: out["submit_error"] = f"{type(e).__name__}: {e}" with open(os.path.join(ROOT, "metadata", "ecds_diagnostic.json"), "w") as f: json.dump(out, f, indent=2, default=str) print(json.dumps({k: out.get(k) for k in ("final_status", "constraints_keys", "constraints_error", "submit_error")}, indent=2, default=str), flush=True) print("\n=== job_json ===", flush=True) print(json.dumps(out.get("job_json", out.get("job_json_error")), indent=2, default=str)[:3000], flush=True)