"""六股统一前瞻PE任务:每输入一行结果,保留局部失败与补查理由。""" import json from decimal import Decimal as D, InvalidOperation SYMBOLS = ["AAA", "BBB", "CCC", "DDD", "EEE", "FFF"] CONTRACT = {"year": 2027, "asof": "2026-10-26", "currency": "CNY", "basis": "diluted"} def finite(value): try: result = D(str(value)) except (InvalidOperation, ValueError, TypeError) as exc: raise ValueError("invalid_numeric_input") from exc if not result.is_finite(): raise ValueError("nonfinite_numeric_field") return result def price_source(symbol): if symbol == "CCC": raise TimeoutError("price_source_timeout") return {"price": {"AAA": "24", "BBB": "30", "DDD": "20", "EEE": "18", "FFF": "15"}[symbol], "asof": CONTRACT["asof"], "currency": "CNY", "source_id": "price:"+symbol} def eps_source(symbol): if symbol == "FFF": return {"summary": "业绩增长稳定"} return {**CONTRACT, "year": 2028 if symbol == "BBB" else 2027, "eps": {"AAA": "1.2", "BBB": "1.5", "DDD": "0", "EEE": "NaN"}[symbol], "source_id": "forecast:"+symbol} def run_one(symbol): out = {**CONTRACT, "symbol": symbol, "status": "failed", "price": None, "eps": None, "pe": None, "reasons": [], "sources": []} try: row = price_source(symbol) if row["asof"] != CONTRACT["asof"] or row["currency"] != "CNY": raise ValueError("price_scope_mismatch") price = finite(row["price"]) if price <= 0: raise ValueError("invalid_price") out.update(price=str(price), status="partial") out["sources"].append(row["source_id"]) except (ValueError, TimeoutError) as exc: out["reasons"].append(str(exc)) return out try: row = eps_source(symbol) if not {"eps", "year", "asof", "currency", "basis", "source_id"} <= row.keys(): raise ValueError("eps_schema_missing_fields") if row["year"] != CONTRACT["year"]: raise ValueError("missing_requested_forecast_year") if any(row[field] != CONTRACT[field] for field in ["asof", "currency", "basis"]): raise ValueError("forecast_scope_mismatch") number = finite(row["eps"]) out["eps"] = str(number) out["sources"].append(row["source_id"]) if number <= 0: raise ValueError("nonpositive_eps_pe_not_applicable") out.update(status="success", pe=str(price/number)) except (ValueError, TimeoutError) as exc: out["reasons"].append(str(exc)) return out results = [run_one(symbol) for symbol in SYMBOLS] assert len(results) == len(SYMBOLS) and [r["symbol"] for r in results] == SYMBOLS assert len({tuple(sorted(r)) for r in results}) == 1 assert results[0]["pe"] == "2E+1" and results[0]["status"] == "success" assert [r["status"] for r in results] == ["success", "partial", "failed", "partial", "partial", "partial"] assert results[2]["price"] is None and results[2]["eps"] is None assert results[3]["eps"] == "0" and results[3]["pe"] is None assert results[4]["price"] == "18" and results[4]["eps"] is None for token in ["NaN", "Infinity", "-Infinity"]: try: finite(token) except ValueError: pass else: raise AssertionError("非有限数必须拒绝") print(json.dumps({"results": results, "counts": {state: sum(r["status"] == state for r in results) for state in ["success", "partial", "failed"]}}, sort_keys=True))