vn6295337 Claude Opus 4.5 commited on
Commit
2901968
·
1 Parent(s): 584203d

Add comprehensive null checks in _extract_and_emit_metrics

Browse files

Fix 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>

Files changed (1) hide show
  1. 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
- if financials.get("net_margin"):
278
- await emit_metric(progress_callback, source, "net_margin", financials["net_margin"])
279
- eps = financials.get("eps", {})
280
- if eps.get("value"):
 
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
- if debt.get("debt_to_equity"):
288
- await emit_metric(progress_callback, source, "debt_to_equity", debt["debt_to_equity"])
 
289
 
290
  elif source == "volatility":
291
- metrics = result.get("metrics", {})
292
- if metrics.get("beta", {}).get("value") is not None:
293
- await emit_metric(progress_callback, source, "beta", metrics["beta"]["value"])
294
- if metrics.get("vix", {}).get("value") is not None:
295
- await emit_metric(progress_callback, source, "VIX", metrics["vix"]["value"])
296
- if metrics.get("historical_volatility", {}).get("value") is not None:
297
- await emit_metric(progress_callback, source, "hist_vol", metrics["historical_volatility"]["value"])
 
 
 
298
 
299
  elif source == "macro":
300
- metrics = result.get("metrics", {})
301
- if metrics.get("gdp_growth", {}).get("value") is not None:
302
- await emit_metric(progress_callback, source, "GDP_growth", metrics["gdp_growth"]["value"])
303
- if metrics.get("interest_rate", {}).get("value") is not None:
304
- await emit_metric(progress_callback, source, "interest_rate", metrics["interest_rate"]["value"])
305
- if metrics.get("cpi_inflation", {}).get("value") is not None:
306
- await emit_metric(progress_callback, source, "inflation", metrics["cpi_inflation"]["value"])
307
- if metrics.get("unemployment", {}).get("value") is not None:
308
- await emit_metric(progress_callback, source, "unemployment", metrics["unemployment"]["value"])
 
 
 
 
309
 
310
  elif source == "valuation":
311
- metrics = result.get("metrics", {})
312
- pe = metrics.get("pe_ratio", {})
313
- pe_val = pe.get("trailing") or pe.get("forward") if isinstance(pe, dict) else pe
 
 
 
 
314
  if pe_val is not None:
315
  await emit_metric(progress_callback, source, "P/E", pe_val)
316
- if metrics.get("pb_ratio") is not None:
317
- await emit_metric(progress_callback, source, "P/B", metrics["pb_ratio"])
318
- if metrics.get("ps_ratio") is not None:
319
- await emit_metric(progress_callback, source, "P/S", metrics["ps_ratio"])
320
- if metrics.get("ev_ebitda") is not None:
321
- await emit_metric(progress_callback, source, "EV/EBITDA", metrics["ev_ebitda"])
 
 
 
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
- if result.get("composite_score") is not None:
333
- await emit_metric(progress_callback, source, "composite_score", result["composite_score"])
 
334
  has_data = True
335
- metrics = result.get("metrics", {})
336
- if metrics.get("finnhub", {}).get("sentiment_score") is not None:
337
- await emit_metric(progress_callback, source, "finnhub_score", metrics["finnhub"]["sentiment_score"])
 
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")