Yesterday wrapped one API. Today wraps three — but each one independently. If Gmail fails, you still want the Calendar and Tasks counts. What's the structure?
Three separate try/except blocks? One for each API call?
Exactly. Each block runs in isolation. Failure in one block sets that source's count to a fallback value but leaves the other two intact. The return dict always has all three keys:
try:
gmail_result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 5})
counts["gmail"] = len(gmail_result.get("messages", []))
except Exception:
counts["gmail"] = -1Using -1 as the sentinel tells the caller 'this source failed' without crashing?
Yes. A sentinel like -1 is distinguishable from 0 (which means 'successfully fetched, found nothing'). The caller can filter failures with if counts[source] >= 0. Here's the full per-API pattern:
def safe_multi_source_counts(max_items: int) -> dict:
counts = {}
try:
gmail_result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": max_items})
counts["gmail"] = len(gmail_result.get("messages", []))
except Exception as exc:
print(f"Gmail failed: {exc}")
counts["gmail"] = -1
try:
cal_result = toolset.execute_action(Action.GOOGLECALENDAR_FIND_EVENT, {"query": ""})
counts["calendar"] = len(cal_result.get("items", []))
except Exception as exc:
print(f"Calendar failed: {exc}")
counts["calendar"] = -1
try:
tasks_result = toolset.execute_action(Action.GOOGLETASKS_LIST_TASKS, {"max_results": max_items})
counts["tasks"] = len(tasks_result.get("items", []))
except Exception as exc:
print(f"Tasks failed: {exc}")
counts["tasks"] = -1
print(f"Safe counts across 3 sources: {counts}")
return countsWhy not wrap everything in one big try/except?
Because that would abort on the first failure. One shared try means a Gmail hiccup wipes out your Calendar and Tasks counts too. Per-API isolation is what lets you gather partial data even when one source is down.
So the caller gets a dict even in the worst case — it might say {"gmail": -1, "calendar": 3, "tasks": 5}, but the function still delivered something usable?
Partial results with a clear sentinel are the production answer when multiple APIs are in play. Week 3's writes and Week 4's pipelines rely on this discipline.
TL;DR: One try/except per API call keeps each source independent — a failure in one doesn't blank out the others.
-1 signals 'this source failed' distinctly from 0| Approach | What happens on first failure |
|---|---|
one shared try | all remaining sources skipped |
one try per API | other sources continue — partial result |
Yesterday wrapped one API. Today wraps three — but each one independently. If Gmail fails, you still want the Calendar and Tasks counts. What's the structure?
Three separate try/except blocks? One for each API call?
Exactly. Each block runs in isolation. Failure in one block sets that source's count to a fallback value but leaves the other two intact. The return dict always has all three keys:
try:
gmail_result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 5})
counts["gmail"] = len(gmail_result.get("messages", []))
except Exception:
counts["gmail"] = -1Using -1 as the sentinel tells the caller 'this source failed' without crashing?
Yes. A sentinel like -1 is distinguishable from 0 (which means 'successfully fetched, found nothing'). The caller can filter failures with if counts[source] >= 0. Here's the full per-API pattern:
def safe_multi_source_counts(max_items: int) -> dict:
counts = {}
try:
gmail_result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": max_items})
counts["gmail"] = len(gmail_result.get("messages", []))
except Exception as exc:
print(f"Gmail failed: {exc}")
counts["gmail"] = -1
try:
cal_result = toolset.execute_action(Action.GOOGLECALENDAR_FIND_EVENT, {"query": ""})
counts["calendar"] = len(cal_result.get("items", []))
except Exception as exc:
print(f"Calendar failed: {exc}")
counts["calendar"] = -1
try:
tasks_result = toolset.execute_action(Action.GOOGLETASKS_LIST_TASKS, {"max_results": max_items})
counts["tasks"] = len(tasks_result.get("items", []))
except Exception as exc:
print(f"Tasks failed: {exc}")
counts["tasks"] = -1
print(f"Safe counts across 3 sources: {counts}")
return countsWhy not wrap everything in one big try/except?
Because that would abort on the first failure. One shared try means a Gmail hiccup wipes out your Calendar and Tasks counts too. Per-API isolation is what lets you gather partial data even when one source is down.
So the caller gets a dict even in the worst case — it might say {"gmail": -1, "calendar": 3, "tasks": 5}, but the function still delivered something usable?
Partial results with a clear sentinel are the production answer when multiple APIs are in play. Week 3's writes and Week 4's pipelines rely on this discipline.
TL;DR: One try/except per API call keeps each source independent — a failure in one doesn't blank out the others.
-1 signals 'this source failed' distinctly from 0| Approach | What happens on first failure |
|---|---|
one shared try | all remaining sources skipped |
one try per API | other sources continue — partial result |
Create a free account to get started. Paid plans unlock all tracks.