xrtm-data 0.7.3__tar.gz → 0.7.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xrtm_data-0.7.3/src/xrtm_data.egg-info → xrtm_data-0.7.4}/PKG-INFO +1 -1
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/pyproject.toml +1 -1
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/online/_http.py +5 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/online/polymarket.py +2 -2
- {xrtm_data-0.7.3 → xrtm_data-0.7.4/src/xrtm_data.egg-info}/PKG-INFO +1 -1
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_online_sources.py +50 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/LICENSE +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/README.md +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/setup.cfg +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/__init__.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/__init__.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/interfaces.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/schemas/__init__.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/schemas/forecast.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/schemas/market.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/schemas/prior.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/schemas/resolution.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/core/schemas/trade.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/corpora/__init__.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/corpora/_builtin_corpora.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/corpora/real_binary.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/corpora/registry.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/__init__.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/online/__init__.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/online/kalshi.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/online/manifold.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/providers/online/metaculus.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm/data/version.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm_data.egg-info/SOURCES.txt +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm_data.egg-info/dependency_links.txt +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm_data.egg-info/requires.txt +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/src/xrtm_data.egg-info/top_level.txt +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_corpus_registry.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_market_snapshot.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_prior_schemas.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_real_binary_corpus.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_resolution_schemas.py +0 -0
- {xrtm_data-0.7.3 → xrtm_data-0.7.4}/tests/test_schemas.py +0 -0
|
@@ -63,6 +63,11 @@ def fetch_json(
|
|
|
63
63
|
last_error = exc
|
|
64
64
|
if exc.code not in RETRYABLE_STATUS or attempt >= retries:
|
|
65
65
|
raise DataSourceError(f"{provider} API error: {exc}") from exc
|
|
66
|
+
except (json.JSONDecodeError, UnicodeDecodeError) as exc:
|
|
67
|
+
# The body was read in full but does not parse: deterministic, so
|
|
68
|
+
# retrying only multiplies the damage (e.g. an HTML maintenance
|
|
69
|
+
# page served with HTTP 200).
|
|
70
|
+
raise DataSourceError(f"{provider} API returned unparseable JSON: {exc}") from exc
|
|
66
71
|
except Exception as exc: # noqa: BLE001 - connection/timeout errors are transient
|
|
67
72
|
last_error = exc
|
|
68
73
|
if attempt >= retries:
|
|
@@ -80,8 +80,8 @@ class PolymarketSource(DataSource, ResolutionSource):
|
|
|
80
80
|
data = self._get_json(url)
|
|
81
81
|
except DataSourceError:
|
|
82
82
|
# Fallback: same markets endpoint without the volume ordering,
|
|
83
|
-
# which some Gamma deployments reject.
|
|
84
|
-
url = f"{self.api_base}/markets?limit={min(limit, 100)}&closed=false"
|
|
83
|
+
# which some Gamma deployments reject. Pagination still applies.
|
|
84
|
+
url = f"{self.api_base}/markets?limit={min(limit, 100)}&offset={offset}&closed=false"
|
|
85
85
|
data = self._get_json(url)
|
|
86
86
|
|
|
87
87
|
# Gamma API may wrap in "markets" key or return list directly
|
|
@@ -277,3 +277,53 @@ def test_fetch_json_does_not_retry_client_errors(monkeypatch):
|
|
|
277
277
|
with pytest.raises(DataSourceError):
|
|
278
278
|
_http.fetch_json("https://example.test/x")
|
|
279
279
|
assert calls["n"] == 1
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def test_fetch_json_does_not_retry_unparseable_bodies(monkeypatch):
|
|
283
|
+
from xrtm.data.providers.online import _http
|
|
284
|
+
|
|
285
|
+
calls = {"n": 0}
|
|
286
|
+
|
|
287
|
+
class _Response:
|
|
288
|
+
def __enter__(self):
|
|
289
|
+
return self
|
|
290
|
+
|
|
291
|
+
def __exit__(self, *args):
|
|
292
|
+
return False
|
|
293
|
+
|
|
294
|
+
def read(self):
|
|
295
|
+
return b"<html>maintenance</html>"
|
|
296
|
+
|
|
297
|
+
def _urlopen(request, timeout=None):
|
|
298
|
+
calls["n"] += 1
|
|
299
|
+
return _Response()
|
|
300
|
+
|
|
301
|
+
monkeypatch.setattr(_http.urllib.request, "urlopen", _urlopen)
|
|
302
|
+
monkeypatch.setattr(_http.time, "sleep", lambda _seconds: None)
|
|
303
|
+
|
|
304
|
+
from xrtm.data import DataSourceError
|
|
305
|
+
|
|
306
|
+
with pytest.raises(DataSourceError, match="unparseable"):
|
|
307
|
+
_http.fetch_json("https://example.test/x")
|
|
308
|
+
assert calls["n"] == 1 # deterministic parse failure: no retries
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@pytest.mark.asyncio
|
|
312
|
+
async def test_polymarket_fallback_keeps_offset(monkeypatch):
|
|
313
|
+
from xrtm.data.core import DataSourceError
|
|
314
|
+
|
|
315
|
+
source = PolymarketSource()
|
|
316
|
+
calls = {"urls": []}
|
|
317
|
+
|
|
318
|
+
def _get_json(url):
|
|
319
|
+
calls["urls"].append(url)
|
|
320
|
+
if "order=volume24hr" in url:
|
|
321
|
+
raise DataSourceError("volume ordering unsupported")
|
|
322
|
+
return []
|
|
323
|
+
|
|
324
|
+
monkeypatch.setattr(source, "_get_json", _get_json)
|
|
325
|
+
|
|
326
|
+
await source.fetch_questions(limit=5, offset=20)
|
|
327
|
+
|
|
328
|
+
assert len(calls["urls"]) == 2
|
|
329
|
+
assert "offset=20" in calls["urls"][1]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|