Files
All-in-one-Financial-Analysis/atlas-terminal/server/services/cache.py
T
shawnkim1997andClaude Opus 4.6 51cbaf7f8d feat: major codebase audit — 21 routers, 37 services, 12 pages fully documented
- Add missing numpy, scipy, dbnomics to requirements.txt (fixes ImportError on fresh install)
- Sync claude.md with actual codebase: §3 file structure (37 services, 21 routers),
  §5 API endpoints (92 routes), §6 frontend pages (12), §13 TODO status
- Update README.md with current architecture (92 API routes, 21 routers, 37 services),
  multi-asset overview, research grid, macro dashboard, screener+backtest,
  multi-jurisdiction filings, and 2026-03-26 changelog entry
- Add new routers: dart, edinet, fmp, macro, research
- Add new services: cache, dart_fetcher, dart_filing_service, economic_calendar,
  ecos_fetcher, edinet_filing_service, fmp_client, global_macro_quadrant,
  kpi_history_service, macro_cycle, macro_fetcher, oecd_cycle,
  peer_comparison_service, research_dashboard, smart_money_service, yield_fx_service
- Add new frontend: macro page, screener+backtest, research grid components,
  overview (Equity/ETF/Commodity), filings (SEC/DART/EDINET), error boundaries
- Remove 6 unused services: copilot_context, crypto_fetcher, fx_fetcher,
  gemini_analysis, market_data, technical_analysis
- Remove obsolete docs: .agent/, AGENT.md, ATLAS_EVALUATION.md, docs/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 21:39:07 +00:00

41 lines
1.0 KiB
Python

"""Simple in-memory TTL cache for expensive macro data fetches."""
from __future__ import annotations
import time
import threading
from typing import Any, Callable, TypeVar
_lock = threading.Lock()
_store: dict[str, tuple[float, Any]] = {}
F = TypeVar("F", bound=Callable)
def cached(key: str, ttl_seconds: int = 3600):
"""Decorator that caches a function result for *ttl_seconds*."""
def decorator(fn: Callable) -> Callable:
def wrapper(*args: Any, **kwargs: Any) -> Any:
now = time.time()
with _lock:
if key in _store:
ts, val = _store[key]
if now - ts < ttl_seconds:
return val
result = fn(*args, **kwargs)
with _lock:
_store[key] = (now, result)
return result
return wrapper
return decorator
def invalidate(key: str) -> None:
with _lock:
_store.pop(key, None)
def invalidate_all() -> None:
with _lock:
_store.clear()