Spaces:
Sleeping
Sleeping
Add comprehensive null checks in _extract_and_emit_metrics
Browse filesFix NoneType errors by using defensive patterns:
- Use `or {}` instead of `.get(key, {})` to handle explicit None values
- Add isinstance() checks before accessing dict methods
- Extract values to variables before checking
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- mcp_client.py +60 -42
mcp_client.py
CHANGED
|
@@ -263,78 +263,96 @@ async def _extract_and_emit_metrics(
|
|
| 263 |
return
|
| 264 |
|
| 265 |
if source == "financials":
|
| 266 |
-
financials = result.get("financials"
|
| 267 |
-
debt = result.get("debt"
|
| 268 |
# Extract temporal data with metrics
|
| 269 |
-
revenue = financials.get("revenue"
|
| 270 |
-
if revenue.get("value"):
|
| 271 |
await emit_metric(
|
| 272 |
progress_callback, source, "revenue", revenue["value"],
|
| 273 |
end_date=revenue.get("end_date"),
|
| 274 |
fiscal_year=revenue.get("fiscal_year"),
|
| 275 |
form=revenue.get("form")
|
| 276 |
)
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
|
|
|
| 281 |
await emit_metric(
|
| 282 |
progress_callback, source, "EPS", eps["value"],
|
| 283 |
end_date=eps.get("end_date"),
|
| 284 |
fiscal_year=eps.get("fiscal_year"),
|
| 285 |
form=eps.get("form")
|
| 286 |
)
|
| 287 |
-
|
| 288 |
-
|
|
|
|
| 289 |
|
| 290 |
elif source == "volatility":
|
| 291 |
-
metrics = result.get("metrics"
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
if
|
| 297 |
-
await emit_metric(progress_callback, source, "
|
|
|
|
|
|
|
|
|
|
| 298 |
|
| 299 |
elif source == "macro":
|
| 300 |
-
metrics = result.get("metrics"
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
if
|
| 306 |
-
await emit_metric(progress_callback, source, "
|
| 307 |
-
|
| 308 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
|
| 310 |
elif source == "valuation":
|
| 311 |
-
metrics = result.get("metrics"
|
| 312 |
-
pe = metrics.get("pe_ratio"
|
| 313 |
-
pe_val =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
if pe_val is not None:
|
| 315 |
await emit_metric(progress_callback, source, "P/E", pe_val)
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
if
|
| 321 |
-
await emit_metric(progress_callback, source, "
|
|
|
|
|
|
|
|
|
|
| 322 |
|
| 323 |
elif source == "news":
|
| 324 |
-
articles = result.get("articles"
|
| 325 |
-
if articles:
|
| 326 |
await emit_metric(progress_callback, source, "articles_found", len(articles))
|
| 327 |
else:
|
| 328 |
await emit_metric(progress_callback, source, "status", "No recent news found")
|
| 329 |
|
| 330 |
elif source == "sentiment":
|
| 331 |
has_data = False
|
| 332 |
-
|
| 333 |
-
|
|
|
|
| 334 |
has_data = True
|
| 335 |
-
metrics = result.get("metrics"
|
| 336 |
-
|
| 337 |
-
|
|
|
|
| 338 |
has_data = True
|
| 339 |
if not has_data:
|
| 340 |
await emit_metric(progress_callback, source, "status", "No sentiment data available")
|
|
|
|
| 263 |
return
|
| 264 |
|
| 265 |
if source == "financials":
|
| 266 |
+
financials = result.get("financials") or {}
|
| 267 |
+
debt = result.get("debt") or {}
|
| 268 |
# Extract temporal data with metrics
|
| 269 |
+
revenue = financials.get("revenue") or {}
|
| 270 |
+
if isinstance(revenue, dict) and revenue.get("value"):
|
| 271 |
await emit_metric(
|
| 272 |
progress_callback, source, "revenue", revenue["value"],
|
| 273 |
end_date=revenue.get("end_date"),
|
| 274 |
fiscal_year=revenue.get("fiscal_year"),
|
| 275 |
form=revenue.get("form")
|
| 276 |
)
|
| 277 |
+
net_margin = financials.get("net_margin") or financials.get("net_margin_pct")
|
| 278 |
+
if net_margin is not None:
|
| 279 |
+
await emit_metric(progress_callback, source, "net_margin", net_margin)
|
| 280 |
+
eps = financials.get("eps") or {}
|
| 281 |
+
if isinstance(eps, dict) and eps.get("value"):
|
| 282 |
await emit_metric(
|
| 283 |
progress_callback, source, "EPS", eps["value"],
|
| 284 |
end_date=eps.get("end_date"),
|
| 285 |
fiscal_year=eps.get("fiscal_year"),
|
| 286 |
form=eps.get("form")
|
| 287 |
)
|
| 288 |
+
debt_to_equity = debt.get("debt_to_equity")
|
| 289 |
+
if debt_to_equity is not None:
|
| 290 |
+
await emit_metric(progress_callback, source, "debt_to_equity", debt_to_equity)
|
| 291 |
|
| 292 |
elif source == "volatility":
|
| 293 |
+
metrics = result.get("metrics") or {}
|
| 294 |
+
beta = metrics.get("beta") or {}
|
| 295 |
+
if isinstance(beta, dict) and beta.get("value") is not None:
|
| 296 |
+
await emit_metric(progress_callback, source, "beta", beta["value"])
|
| 297 |
+
vix = metrics.get("vix") or {}
|
| 298 |
+
if isinstance(vix, dict) and vix.get("value") is not None:
|
| 299 |
+
await emit_metric(progress_callback, source, "VIX", vix["value"])
|
| 300 |
+
hist_vol = metrics.get("historical_volatility") or {}
|
| 301 |
+
if isinstance(hist_vol, dict) and hist_vol.get("value") is not None:
|
| 302 |
+
await emit_metric(progress_callback, source, "hist_vol", hist_vol["value"])
|
| 303 |
|
| 304 |
elif source == "macro":
|
| 305 |
+
metrics = result.get("metrics") or {}
|
| 306 |
+
gdp = metrics.get("gdp_growth") or {}
|
| 307 |
+
if isinstance(gdp, dict) and gdp.get("value") is not None:
|
| 308 |
+
await emit_metric(progress_callback, source, "GDP_growth", gdp["value"])
|
| 309 |
+
interest = metrics.get("interest_rate") or {}
|
| 310 |
+
if isinstance(interest, dict) and interest.get("value") is not None:
|
| 311 |
+
await emit_metric(progress_callback, source, "interest_rate", interest["value"])
|
| 312 |
+
inflation = metrics.get("cpi_inflation") or {}
|
| 313 |
+
if isinstance(inflation, dict) and inflation.get("value") is not None:
|
| 314 |
+
await emit_metric(progress_callback, source, "inflation", inflation["value"])
|
| 315 |
+
unemployment = metrics.get("unemployment") or {}
|
| 316 |
+
if isinstance(unemployment, dict) and unemployment.get("value") is not None:
|
| 317 |
+
await emit_metric(progress_callback, source, "unemployment", unemployment["value"])
|
| 318 |
|
| 319 |
elif source == "valuation":
|
| 320 |
+
metrics = result.get("metrics") or {}
|
| 321 |
+
pe = metrics.get("pe_ratio") or {}
|
| 322 |
+
pe_val = None
|
| 323 |
+
if isinstance(pe, dict):
|
| 324 |
+
pe_val = pe.get("trailing") or pe.get("forward")
|
| 325 |
+
elif isinstance(pe, (int, float)):
|
| 326 |
+
pe_val = pe
|
| 327 |
if pe_val is not None:
|
| 328 |
await emit_metric(progress_callback, source, "P/E", pe_val)
|
| 329 |
+
pb_ratio = metrics.get("pb_ratio")
|
| 330 |
+
if pb_ratio is not None:
|
| 331 |
+
await emit_metric(progress_callback, source, "P/B", pb_ratio)
|
| 332 |
+
ps_ratio = metrics.get("ps_ratio")
|
| 333 |
+
if ps_ratio is not None:
|
| 334 |
+
await emit_metric(progress_callback, source, "P/S", ps_ratio)
|
| 335 |
+
ev_ebitda = metrics.get("ev_ebitda")
|
| 336 |
+
if ev_ebitda is not None:
|
| 337 |
+
await emit_metric(progress_callback, source, "EV/EBITDA", ev_ebitda)
|
| 338 |
|
| 339 |
elif source == "news":
|
| 340 |
+
articles = result.get("articles") or []
|
| 341 |
+
if articles and isinstance(articles, list) and len(articles) > 0:
|
| 342 |
await emit_metric(progress_callback, source, "articles_found", len(articles))
|
| 343 |
else:
|
| 344 |
await emit_metric(progress_callback, source, "status", "No recent news found")
|
| 345 |
|
| 346 |
elif source == "sentiment":
|
| 347 |
has_data = False
|
| 348 |
+
composite = result.get("composite_score")
|
| 349 |
+
if composite is not None:
|
| 350 |
+
await emit_metric(progress_callback, source, "composite_score", composite)
|
| 351 |
has_data = True
|
| 352 |
+
metrics = result.get("metrics") or {}
|
| 353 |
+
finnhub = metrics.get("finnhub") or {}
|
| 354 |
+
if isinstance(finnhub, dict) and finnhub.get("sentiment_score") is not None:
|
| 355 |
+
await emit_metric(progress_callback, source, "finnhub_score", finnhub["sentiment_score"])
|
| 356 |
has_data = True
|
| 357 |
if not has_data:
|
| 358 |
await emit_metric(progress_callback, source, "status", "No sentiment data available")
|