xrtm-data 0.7.0__tar.gz → 0.7.2__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.
Files changed (37) hide show
  1. {xrtm_data-0.7.0/src/xrtm_data.egg-info → xrtm_data-0.7.2}/PKG-INFO +1 -1
  2. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/pyproject.toml +1 -1
  3. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/corpora/real_binary.py +10 -1
  4. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/providers/online/kalshi.py +1 -1
  5. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/providers/online/manifold.py +1 -2
  6. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/providers/online/polymarket.py +3 -2
  7. {xrtm_data-0.7.0 → xrtm_data-0.7.2/src/xrtm_data.egg-info}/PKG-INFO +1 -1
  8. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_online_sources.py +57 -0
  9. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_real_binary_corpus.py +13 -0
  10. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/LICENSE +0 -0
  11. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/README.md +0 -0
  12. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/setup.cfg +0 -0
  13. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/__init__.py +0 -0
  14. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/__init__.py +0 -0
  15. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/interfaces.py +0 -0
  16. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/schemas/__init__.py +0 -0
  17. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/schemas/forecast.py +0 -0
  18. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/schemas/market.py +0 -0
  19. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/schemas/prior.py +0 -0
  20. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/schemas/resolution.py +0 -0
  21. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/core/schemas/trade.py +0 -0
  22. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/corpora/__init__.py +0 -0
  23. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/corpora/_builtin_corpora.py +0 -0
  24. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/corpora/registry.py +0 -0
  25. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/providers/__init__.py +0 -0
  26. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/providers/online/__init__.py +0 -0
  27. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/providers/online/metaculus.py +0 -0
  28. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm/data/version.py +0 -0
  29. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm_data.egg-info/SOURCES.txt +0 -0
  30. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm_data.egg-info/dependency_links.txt +0 -0
  31. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm_data.egg-info/requires.txt +0 -0
  32. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/src/xrtm_data.egg-info/top_level.txt +0 -0
  33. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_corpus_registry.py +0 -0
  34. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_market_snapshot.py +0 -0
  35. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_prior_schemas.py +0 -0
  36. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_resolution_schemas.py +0 -0
  37. {xrtm_data-0.7.0 → xrtm_data-0.7.2}/tests/test_schemas.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xrtm-data
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: The Snapshot Vault for XRTM.
5
5
  Author-email: XRTM Team <moy@xrtm.org>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "xrtm-data"
7
- version = "0.7.0"
7
+ version = "0.7.2"
8
8
  description = "The Snapshot Vault for XRTM."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.13"
@@ -33,7 +33,7 @@ from typing import Any, Mapping, Optional, Sequence
33
33
 
34
34
  from pydantic import BaseModel, ConfigDict, Field, model_validator
35
35
 
36
- from xrtm.data.core import DataSource
36
+ from xrtm.data.core import DataSource, SourceTemporalIntegrityError
37
37
  from xrtm.data.core.schemas import ForecastQuestion, MetadataBase
38
38
 
39
39
  REAL_BINARY_CORPUS_ID = "xrtm-real-binary-v1"
@@ -498,6 +498,11 @@ class RealBinaryCorpusSource(DataSource):
498
498
  self, query: Optional[str] = None, limit: int = 5, *, snapshot_time: Optional[datetime] = None
499
499
  ) -> list[ForecastQuestion]:
500
500
  r"""Fetch deterministic corpus questions, optionally filtering title/content text."""
501
+ if snapshot_time is not None:
502
+ raise SourceTemporalIntegrityError(
503
+ "RealBinaryCorpusSource cannot honour snapshot_time; it returns the embedded corpus "
504
+ "as-is. Use a time-aware source or omit the snapshot."
505
+ )
501
506
  query_lower = query.lower() if query else None
502
507
  matches: list[ForecastQuestion] = []
503
508
  for question in self._questions:
@@ -512,6 +517,10 @@ class RealBinaryCorpusSource(DataSource):
512
517
  self, question_id: str, *, snapshot_time: Optional[datetime] = None
513
518
  ) -> Optional[ForecastQuestion]:
514
519
  r"""Retrieve a deterministic corpus question by id."""
520
+ if snapshot_time is not None:
521
+ raise SourceTemporalIntegrityError(
522
+ "RealBinaryCorpusSource cannot honour snapshot_time; it returns the embedded corpus as-is."
523
+ )
515
524
  question = self._questions_by_id.get(question_id)
516
525
  if question is None:
517
526
  return None
@@ -177,7 +177,7 @@ class KalshiSource(DataSource, ResolutionSource):
177
177
  title=title[:500] or ticker,
178
178
  description=f"{subtitle[:500]}\n\n{price_info}".strip(),
179
179
  metadata=MetadataBase(
180
- snapshot_time=_parse_ts(item.get("close_time")) if item.get("close_time") else datetime.now(timezone.utc),
180
+ snapshot_time=datetime.now(timezone.utc), # fetch time; close_time is in the future
181
181
  source_version="kalshi",
182
182
  tags=["kalshi", "binary", "prediction-market"],
183
183
  raw_data={
@@ -163,14 +163,13 @@ class ManifoldSource(DataSource, ResolutionSource):
163
163
  market_id = str(item.get("id", ""))
164
164
  probability = item.get("probability")
165
165
  price_info = f"Current probability: {float(probability)*100:.1f}%" if probability is not None else ""
166
- close_time = item.get("closeTime")
167
166
 
168
167
  return ForecastQuestion(
169
168
  id=f"manifold-{market_id}",
170
169
  title=str(item.get("question", ""))[:500],
171
170
  description=f"Manifold market {market_id}. {price_info}".strip(),
172
171
  metadata=MetadataBase(
173
- snapshot_time=_parse_ts(close_time) if close_time else datetime.now(timezone.utc),
172
+ snapshot_time=datetime.now(timezone.utc), # fetch time; close_time is in the future
174
173
  source_version="manifold",
175
174
  tags=["manifold", "binary", "prediction-market"],
176
175
  raw_data={
@@ -79,8 +79,9 @@ class PolymarketSource(DataSource, ResolutionSource):
79
79
  try:
80
80
  data = self._get_json(url)
81
81
  except DataSourceError:
82
- # Gamma API may return a list directly
83
- url = f"{self.api_base}/events?limit={min(limit, 50)}&closed=false"
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"
84
85
  data = self._get_json(url)
85
86
 
86
87
  # Gamma API may wrap in "markets" key or return list directly
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xrtm-data
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: The Snapshot Vault for XRTM.
5
5
  Author-email: XRTM Team <moy@xrtm.org>
6
6
  License-Expression: Apache-2.0
@@ -28,6 +28,28 @@ def test_sources_implement_resolution_interface():
28
28
  assert isinstance(source, ResolutionSource)
29
29
 
30
30
 
31
+ @pytest.mark.asyncio
32
+ async def test_manifold_snapshot_time_is_fetch_time(monkeypatch):
33
+ from datetime import datetime, timedelta, timezone
34
+
35
+ source = ManifoldSource()
36
+ monkeypatch.setattr(
37
+ source,
38
+ "_get_json",
39
+ lambda url: [
40
+ {"id": "abc", "question": "Will X?", "isResolved": False, "closeTime": 4102444800000}, # year 2100
41
+ ],
42
+ )
43
+
44
+ questions = await source.fetch_questions(limit=1)
45
+
46
+ assert questions
47
+ snapshot = questions[0].metadata.snapshot_time
48
+ assert snapshot is not None
49
+ # Snapshot must be the fetch time, never the (future) close time.
50
+ assert snapshot <= datetime.now(timezone.utc) + timedelta(seconds=5)
51
+
52
+
31
53
  @pytest.mark.asyncio
32
54
  async def test_manifold_fetch_resolved_maps_yes_no(monkeypatch):
33
55
  source = ManifoldSource()
@@ -172,3 +194,38 @@ async def test_kalshi_fetch_resolved_paginates_cursor(monkeypatch):
172
194
 
173
195
  assert len(resolved) == 250
174
196
  assert calls["count"] == 2
197
+
198
+
199
+ @pytest.mark.asyncio
200
+ async def test_polymarket_fetch_questions_fallback_uses_markets(monkeypatch):
201
+ from xrtm.data.core import DataSourceError
202
+
203
+ source = PolymarketSource()
204
+ calls = {"urls": []}
205
+
206
+ def _get_json(url):
207
+ calls["urls"].append(url)
208
+ if "order=volume24hr" in url:
209
+ raise DataSourceError("volume ordering unsupported")
210
+ return [
211
+ {
212
+ "id": "m1",
213
+ "question": "Will X happen?",
214
+ "description": "d",
215
+ "outcomes": '["Yes", "No"]',
216
+ "outcomePrices": '["0.6", "0.4"]',
217
+ "volume": 1000,
218
+ "liquidity": 500,
219
+ "endDate": "2026-12-31T00:00:00Z",
220
+ "slug": "will-x",
221
+ "closed": False,
222
+ }
223
+ ]
224
+
225
+ monkeypatch.setattr(source, "_get_json", _get_json)
226
+
227
+ questions = await source.fetch_questions(limit=1)
228
+
229
+ assert len(calls["urls"]) == 2
230
+ assert "/markets?" in calls["urls"][1]
231
+ assert questions and questions[0].id == "polymarket-m1"
@@ -26,6 +26,19 @@ from xrtm.data.corpora import (
26
26
  )
27
27
 
28
28
 
29
+ @pytest.mark.asyncio
30
+ async def test_real_binary_corpus_source_rejects_snapshot_time():
31
+ from datetime import datetime
32
+
33
+ from xrtm.data import SourceTemporalIntegrityError
34
+
35
+ source = RealBinaryCorpusSource()
36
+ with pytest.raises(SourceTemporalIntegrityError):
37
+ await source.fetch_questions(limit=1, snapshot_time=datetime(2026, 1, 1))
38
+ with pytest.raises(SourceTemporalIntegrityError):
39
+ await source.get_question_by_id("any", snapshot_time=datetime(2026, 1, 1))
40
+
41
+
29
42
  def test_real_binary_corpus_shape_and_resolution_coverage():
30
43
  records = load_real_binary_corpus()
31
44
 
File without changes
File without changes
File without changes