fix: resolve all mypy type errors for strict type checking (#48)

## Summary

Fixed 30 mypy type errors across 8 files to enable strict type checking.

## Changes by Category

### no-any-return errors (fixed with explicit type casts)
- alerter/history.py: Cast Redis zcount/zremrangebyscore returns to int
- ingestor/clob_client.py: Cast API response values appropriately
- ingestor/publisher.py: Cast Redis xack, xlen, xtrim returns to int
- ingestor/metadata_sync.py: Cast Redis delete return to int
- detector/scorer.py: Cast Redis delete return to int

### operator errors (fixed with null checks)
- alerter/formatter.py: Added `if age_hours is not None:` guards

### External library typing issues (fixed with type: ignore)
- ingestor/publisher.py: redis-py typing issue with xadd dict parameter
- profiler/funding.py: web3 typing issue with block parameters
- storage/repos.py: SQLAlchemy Result.rowcount typing issue

### assignment errors (fixed by renaming)
- storage/repos.py: Renamed SQLite insert stmt to avoid type conflict

Closes #48

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Patrick Selamy
2026-01-04 19:15:32 -05:00
co-authored by Claude Opus 4.5
parent f57e0243dd
commit 5c5440d776
8 changed files with 60 additions and 45 deletions
@@ -287,7 +287,8 @@ class ClobClient:
try:
response = self._client.get_midpoint(token_id)
return response.get("mid")
mid = response.get("mid")
return str(mid) if mid is not None else None
except Exception as e:
logger.warning("Failed to get midpoint for %s: %s", token_id, e)
return None
@@ -307,7 +308,8 @@ class ClobClient:
try:
response = self._client.get_price(token_id, side=side)
return response.get("price")
price = response.get("price")
return str(price) if price is not None else None
except Exception as e:
logger.warning("Failed to get %s price for %s: %s", side, token_id, e)
return None
@@ -321,7 +323,7 @@ class ClobClient:
try:
self._rate_limiter.acquire_sync()
result = self._client.get_ok()
return result == "OK"
return str(result) == "OK"
except Exception as e:
logger.error("Health check failed: %s", e)
return False
@@ -334,7 +336,8 @@ class ClobClient:
"""
try:
self._rate_limiter.acquire_sync()
return self._client.get_server_time()
result = self._client.get_server_time()
return int(result) if result is not None else None
except Exception as e:
logger.error("Failed to get server time: %s", e)
return None
@@ -351,7 +351,7 @@ class MarketMetadataSync:
"""
key = f"{self._key_prefix}{condition_id}"
deleted = await self._redis.delete(key)
return deleted > 0
return int(deleted) > 0
async def force_sync(self) -> None:
"""Force an immediate sync of all markets.
@@ -186,9 +186,10 @@ class EventPublisher:
The entry ID assigned by Redis.
"""
data = _serialize_trade_event(event)
# redis-py typing expects broader dict type than dict[str, str]
entry_id = await self._redis.xadd(
self._stream_name,
data,
data, # type: ignore[arg-type]
maxlen=self._max_len,
)
# entry_id may be bytes or str
@@ -213,7 +214,8 @@ class EventPublisher:
pipe = self._redis.pipeline()
for event in events:
data = _serialize_trade_event(event)
pipe.xadd(self._stream_name, data, maxlen=self._max_len)
# redis-py typing expects broader dict type than dict[str, str]
pipe.xadd(self._stream_name, data, maxlen=self._max_len) # type: ignore[arg-type]
results = await pipe.execute()
@@ -384,7 +386,8 @@ class EventPublisher:
"""
if not entry_ids:
return 0
return await self._redis.xack(self._stream_name, group_name, *entry_ids)
result = await self._redis.xack(self._stream_name, group_name, *entry_ids)
return int(result)
async def get_stream_info(self) -> dict[str, Any]:
"""Get information about the stream.
@@ -404,7 +407,8 @@ class EventPublisher:
Returns:
Number of entries in the stream.
"""
return await self._redis.xlen(self._stream_name)
result = await self._redis.xlen(self._stream_name)
return int(result)
async def trim_stream(self, max_len: int | None = None) -> int:
"""Trim the stream to a maximum length.
@@ -416,4 +420,5 @@ class EventPublisher:
Number of entries removed.
"""
length = max_len or self._max_len
return await self._redis.xtrim(self._stream_name, maxlen=length)
result = await self._redis.xtrim(self._stream_name, maxlen=length)
return int(result)