from abc import ABC, abstractmethod
from contextlib import contextmanager
-from typing import Iterator
+from sys import stderr
+from typing import IO, Iterator
import requests
import requests_cache
return r.content
+class _CachingFetcher(Fetcher):
+
+ def __init__(
+ self,
+ session: requests_cache.CachedSession,
+ timeout: int) -> None:
+ self._session = session
+ self._timeout = timeout
+ self._request_count = 0
+ self._cache_hit_count = 0
+
+ def fetch(self, url: str) -> bytes:
+ with self._session.get(url, timeout=self._timeout) as r:
+ r.raise_for_status()
+ self._request_count += 1
+ self._cache_hit_count += int(r.from_cache)
+ return r.content
+
+ @property
+ def request_count(self) -> int:
+ return self._request_count
+
+ @property
+ def cache_hit_count(self) -> int:
+ return self._cache_hit_count
+
+
@contextmanager
def DirectFetcher(timeout: int) -> Iterator[_SessionFetcher]:
with requests.session() as session:
@contextmanager
-def CachingFetcher(cache_path: str, timeout: int) -> Iterator[_SessionFetcher]:
+def CachingFetcher(
+ cache_path: str,
+ timeout: int,
+ report_stream: IO[str] = stderr) -> Iterator[_CachingFetcher]:
with requests_cache.CachedSession(cache_path, cache_control=True) as session:
- yield _SessionFetcher(session, timeout)
+ fetcher = _CachingFetcher(session, timeout)
+ yield fetcher
+ if fetcher.request_count > 0:
+ percent = 100.0 * fetcher.cache_hit_count / fetcher.request_count
+ print(
+ f"Fetch cache hits: {fetcher.cache_hit_count} ({percent:.1f}%)",
+ file=report_stream)
class FakeFetcher(Fetcher):