Skip to content

Commit af9e369

Browse files
committed
upd
1 parent 618b729 commit af9e369

1 file changed

Lines changed: 41 additions & 26 deletions

File tree

slopmortem/corpus/sources/defillama.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import logging
1010
from dataclasses import dataclass
1111
from datetime import UTC, date, datetime, timedelta
12-
from typing import TYPE_CHECKING, Any, Final, Literal, cast
12+
from typing import TYPE_CHECKING, Final, Literal, cast
1313
from urllib.parse import urlencode
1414

1515
import httpx
@@ -54,24 +54,30 @@ class DeathVerdict:
5454
current_tvl: float | None = None
5555

5656

57-
def _merge_chain_series(chain_tvls: dict[str, dict[str, Any]]) -> list[tuple[date, float]]: # pyright: ignore[reportExplicitAny]
57+
def _str_or_empty(value: object) -> str:
58+
return value if isinstance(value, str) else ""
59+
60+
61+
def _merge_chain_series(chain_tvls: dict[str, object]) -> list[tuple[date, float]]:
5862
"""Sum daily totalLiquidityUSD across chains; dedupe intra-day duplicates last-write-wins.
5963
6064
DefiLlama ships multiple "today" snapshots; naive summing double-counts current TVL.
6165
"""
6266
totals: dict[date, float] = {}
6367
for chain_payload in chain_tvls.values():
64-
if not isinstance(chain_payload, dict): # pyright: ignore[reportUnnecessaryIsInstance] — runtime defence; Any values are not statically narrowable
68+
if not isinstance(chain_payload, dict):
6569
continue
66-
series_obj: object = chain_payload.get("tvl")
70+
chain_dict = cast("dict[str, object]", chain_payload)
71+
series_obj: object = chain_dict.get("tvl")
6772
if not isinstance(series_obj, list):
6873
continue
6974
per_day: dict[date, float] = {}
70-
for point in series_obj: # pyright: ignore[reportUnknownVariableType] — list[Any] from JSON
71-
if not isinstance(point, dict):
75+
for raw_point in cast("list[object]", series_obj):
76+
if not isinstance(raw_point, dict):
7277
continue
73-
ts: object = point.get("date") # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType] — Any from JSON
74-
tvl: object = point.get("totalLiquidityUSD") # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType] — Any from JSON
78+
point = cast("dict[str, object]", raw_point)
79+
ts: object = point.get("date")
80+
tvl: object = point.get("totalLiquidityUSD")
7581
if not isinstance(ts, (int, float)) or not isinstance(tvl, (int, float)):
7682
continue
7783
d = datetime.fromtimestamp(float(ts), tz=UTC).date()
@@ -82,7 +88,7 @@ def _merge_chain_series(chain_tvls: dict[str, dict[str, Any]]) -> list[tuple[dat
8288

8389

8490
def classify_death(
85-
chain_tvls: dict[str, dict[str, Any]], # pyright: ignore[reportExplicitAny]
91+
chain_tvls: dict[str, object],
8692
*,
8793
threshold_pct: float = DEFAULT_DEAD_THRESHOLD_PCT,
8894
peak_floor_usd: float = DEFAULT_PEAK_FLOOR_USD,
@@ -173,12 +179,15 @@ async def wayback_snapshot_near(
173179
return None
174180

175181

176-
def _seed_markdown(detail: dict[str, Any], verdict: DeathVerdict) -> str: # pyright: ignore[reportExplicitAny]
182+
def _seed_markdown(
183+
*,
184+
name: str,
185+
category: str,
186+
chain: str,
187+
description: str,
188+
verdict: DeathVerdict,
189+
) -> str:
177190
"""Minimal pitch-shaped seed text. TavilyEnricher fills the real body from Wayback."""
178-
name: object = detail.get("name") or ""
179-
category: object = detail.get("category") or ""
180-
chain: object = detail.get("chain") or ""
181-
description: object = detail.get("description") or ""
182191
parts = [
183192
f"# {name}",
184193
"",
@@ -188,7 +197,7 @@ def _seed_markdown(detail: dict[str, Any], verdict: DeathVerdict) -> str: # pyr
188197
f"peak_date: {verdict.peak_date}",
189198
f"tvl_current_usd: {verdict.current_tvl}",
190199
"",
191-
str(description),
200+
description,
192201
]
193202
return "\n".join(parts).strip()
194203

@@ -234,18 +243,17 @@ async def _fetch_json(self, url: str) -> object | None:
234243
logger.warning("defillama: non-JSON response for %s: %r", url, exc)
235244
return None
236245

237-
async def _classify_candidate(
238-
self, slug: str, live_url: str
239-
) -> tuple[dict[str, Any], DeathVerdict, str] | None: # pyright: ignore[reportExplicitAny]
246+
async def _classify_candidate(self, slug: str, live_url: str) -> tuple[str, str] | None:
247+
"""Fetch detail, classify, anchor to Wayback. Return (markdown_body, snapshot_url)."""
240248
detail_payload = await self._fetch_json(f"{DETAIL_ENDPOINT_BASE}/{slug}")
241249
if not isinstance(detail_payload, dict):
242250
return None
243-
detail = cast("dict[str, Any]", detail_payload) # pyright: ignore[reportExplicitAny]
251+
detail = cast("dict[str, object]", detail_payload)
244252

245-
chain_tvls_raw: object = detail.get("chainTvls") or {}
253+
chain_tvls_raw: object = detail.get("chainTvls")
246254
if not isinstance(chain_tvls_raw, dict):
247255
return None
248-
chain_tvls = cast("dict[str, dict[str, Any]]", chain_tvls_raw) # pyright: ignore[reportExplicitAny]
256+
chain_tvls = cast("dict[str, object]", chain_tvls_raw)
249257

250258
verdict = classify_death(
251259
chain_tvls,
@@ -264,9 +272,16 @@ async def _classify_candidate(
264272
logger.info("defillama: %s no wayback coverage near %s", slug, verdict.peak_date)
265273
return None
266274

267-
return detail, verdict, snapshot_url
275+
body = _seed_markdown(
276+
name=_str_or_empty(detail.get("name")),
277+
category=_str_or_empty(detail.get("category")),
278+
chain=_str_or_empty(detail.get("chain")),
279+
description=_str_or_empty(detail.get("description")),
280+
verdict=verdict,
281+
)
282+
return body, snapshot_url
268283

269-
async def _process_candidate(self, row: dict[str, Any]) -> RawEntry | None: # pyright: ignore[reportExplicitAny]
284+
async def _process_candidate(self, row: dict[str, object]) -> RawEntry | None:
270285
slug: object = row.get("slug")
271286
live_url: object = row.get("url")
272287
if not isinstance(slug, str) or not slug:
@@ -278,14 +293,14 @@ async def _process_candidate(self, row: dict[str, Any]) -> RawEntry | None: # p
278293
result = await self._classify_candidate(slug, live_url)
279294
if result is None:
280295
return None
281-
detail, verdict, snapshot_url = result
296+
markdown_text, snapshot_url = result
282297

283298
return RawEntry(
284299
source=SOURCE_DEFILLAMA,
285300
source_id=slug,
286301
url=snapshot_url,
287302
raw_html=None,
288-
markdown_text=_seed_markdown(detail, verdict),
303+
markdown_text=markdown_text,
289304
fetched_at=datetime.now(UTC),
290305
)
291306

@@ -303,7 +318,7 @@ async def fetch(self) -> AsyncIterator[RawEntry]:
303318
return
304319
if not isinstance(raw, dict):
305320
continue
306-
row = cast("dict[str, Any]", raw) # pyright: ignore[reportExplicitAny]
321+
row = cast("dict[str, object]", raw)
307322
tvl_field: object = row.get("tvl")
308323
if not isinstance(tvl_field, (int, float)):
309324
continue

0 commit comments

Comments
 (0)