everestapi 0.2.0__tar.gz → 0.2.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 (22) hide show
  1. {everestapi-0.2.0/src/everestapi.egg-info → everestapi-0.2.2}/PKG-INFO +6 -6
  2. {everestapi-0.2.0 → everestapi-0.2.2}/README.md +2 -2
  3. {everestapi-0.2.0 → everestapi-0.2.2}/pyproject.toml +3 -3
  4. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/__init__.py +1 -1
  5. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/cli.py +26 -19
  6. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/client.py +85 -44
  7. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/mcp/server.py +112 -36
  8. {everestapi-0.2.0 → everestapi-0.2.2/src/everestapi.egg-info}/PKG-INFO +6 -6
  9. {everestapi-0.2.0 → everestapi-0.2.2}/tests/test_cli.py +1 -0
  10. {everestapi-0.2.0 → everestapi-0.2.2}/tests/test_client.py +5 -2
  11. {everestapi-0.2.0 → everestapi-0.2.2}/tests/test_mcp_and_models.py +31 -11
  12. {everestapi-0.2.0 → everestapi-0.2.2}/LICENSE +0 -0
  13. {everestapi-0.2.0 → everestapi-0.2.2}/setup.cfg +0 -0
  14. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/__main__.py +0 -0
  15. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/mcp/__init__.py +0 -0
  16. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/mcp/__main__.py +0 -0
  17. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi/types.py +0 -0
  18. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi.egg-info/SOURCES.txt +0 -0
  19. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi.egg-info/dependency_links.txt +0 -0
  20. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi.egg-info/entry_points.txt +0 -0
  21. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi.egg-info/requires.txt +0 -0
  22. {everestapi-0.2.0 → everestapi-0.2.2}/src/everestapi.egg-info/top_level.txt +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: everestapi
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Python SDK for the EverestQuant prediction tournament platform
5
- Author-email: EverestQuant <engineering@everestquant.ai>
5
+ Author-email: EverestQuant <support@everesteer.ai>
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://everestquant.ai
8
- Project-URL: Documentation, https://docs.everestquant.ai
7
+ Project-URL: Homepage, https://everesteer.ai
8
+ Project-URL: Documentation, https://docs.everesteer.ai
9
9
  Project-URL: Repository, https://github.com/everestquant/everestapi-public
10
10
  Keywords: quant,tournament,prediction,staking,machine-learning
11
11
  Classifier: Development Status :: 4 - Beta
@@ -30,7 +30,7 @@ Dynamic: license-file
30
30
 
31
31
  # everestapi
32
32
 
33
- Python SDK for the [EverestQuant](https://everestquant.ai) prediction tournament platform.
33
+ Python SDK for the [EverestQuant](https://everesteer.ai) prediction tournament platform.
34
34
 
35
35
  ```bash
36
36
  pip install everestapi
@@ -59,7 +59,7 @@ api.submit_futures_predictions(
59
59
  scores = api.get_scores(model_id="my-model", days=30)
60
60
  ```
61
61
 
62
- Or set `EVEREST_API_KEY` as an environment variable and omit the constructor argument.
62
+ Or set `EIQ_API_KEY` as an environment variable and omit the constructor argument.
63
63
 
64
64
  > **Handling your API key.** Shell history, terminal recordings, and CI logs may persist any value you `echo` or `print`. Copy the key via the clipboard rather than echoing it in a recorded session, and prefer storing it in a secrets manager or `.env` file (gitignored) over inlining in source.
65
65
 
@@ -1,6 +1,6 @@
1
1
  # everestapi
2
2
 
3
- Python SDK for the [EverestQuant](https://everestquant.ai) prediction tournament platform.
3
+ Python SDK for the [EverestQuant](https://everesteer.ai) prediction tournament platform.
4
4
 
5
5
  ```bash
6
6
  pip install everestapi
@@ -29,7 +29,7 @@ api.submit_futures_predictions(
29
29
  scores = api.get_scores(model_id="my-model", days=30)
30
30
  ```
31
31
 
32
- Or set `EVEREST_API_KEY` as an environment variable and omit the constructor argument.
32
+ Or set `EIQ_API_KEY` as an environment variable and omit the constructor argument.
33
33
 
34
34
  > **Handling your API key.** Shell history, terminal recordings, and CI logs may persist any value you `echo` or `print`. Copy the key via the clipboard rather than echoing it in a recorded session, and prefer storing it in a secrets manager or `.env` file (gitignored) over inlining in source.
35
35
 
@@ -9,7 +9,7 @@ description = "Python SDK for the EverestQuant prediction tournament platform"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.10"
12
- authors = [{ name = "EverestQuant", email = "engineering@everestquant.ai" }]
12
+ authors = [{ name = "EverestQuant", email = "support@everesteer.ai" }]
13
13
  keywords = ["quant", "tournament", "prediction", "staking", "machine-learning"]
14
14
  classifiers = [
15
15
  "Development Status :: 4 - Beta",
@@ -36,8 +36,8 @@ mcp = ["mcp>=1.0"]
36
36
  everestapi = "everestapi.cli:cli"
37
37
 
38
38
  [project.urls]
39
- Homepage = "https://everestquant.ai"
40
- Documentation = "https://docs.everestquant.ai"
39
+ Homepage = "https://everesteer.ai"
40
+ Documentation = "https://docs.everesteer.ai"
41
41
  Repository = "https://github.com/everestquant/everestapi-public"
42
42
 
43
43
  [tool.setuptools.packages.find]
@@ -1,6 +1,6 @@
1
1
  """EverestAPI — Python SDK for the EverestQuant prediction tournament platform."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.2"
4
4
 
5
5
  from everestapi.client import EverestAPI, EverestError
6
6
  from everestapi.types import (
@@ -36,7 +36,7 @@ def cli() -> None:
36
36
 
37
37
 
38
38
  @cli.command()
39
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
39
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
40
40
  def health(api_key: str | None) -> None:
41
41
  """Check API health."""
42
42
  api = _get_api(api_key)
@@ -51,7 +51,7 @@ def health(api_key: str | None) -> None:
51
51
  @click.option("--universe", "-u", default="futures", help="Universe (futures/equities)")
52
52
  @click.option("--split", "-s", default="train", help="Split (train/validation/test/live)")
53
53
  @click.option("--output", "-o", default=None, help="Output file path")
54
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
54
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
55
55
  def download_data(universe: str, split: str, output: str | None, api_key: str | None) -> None:
56
56
  """Download tournament dataset."""
57
57
  api = _get_api(api_key)
@@ -68,12 +68,16 @@ def download_data(universe: str, split: str, output: str | None, api_key: str |
68
68
  @click.option("--split", "-s", default="validation")
69
69
  @click.option("--version", "-v", default="v0")
70
70
  @click.option("--output", "-o", default=None)
71
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
72
- def download_benchmark(universe: str, split: str, version: str, output: str | None, api_key: str | None) -> None:
71
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
72
+ def download_benchmark(
73
+ universe: str, split: str, version: str, output: str | None, api_key: str | None
74
+ ) -> None:
73
75
  """Download benchmark model predictions."""
74
76
  api = _get_api(api_key)
75
77
  try:
76
- path = api.download_benchmark(universe=universe, split=split, version=version, output_path=output)
78
+ path = api.download_benchmark(
79
+ universe=universe, split=split, version=version, output_path=output
80
+ )
77
81
  click.echo(f"Downloaded to {path}")
78
82
  except EverestError as e:
79
83
  click.echo(f"Error: {e}", err=True)
@@ -83,12 +87,14 @@ def download_benchmark(universe: str, split: str, version: str, output: str | No
83
87
  @cli.command()
84
88
  @click.option("--model", "-m", required=True, help="Model identifier")
85
89
  @click.option(
86
- "--file", "-f", "file_path",
90
+ "--file",
91
+ "-f",
92
+ "file_path",
87
93
  required=True,
88
94
  help="Predictions file (.parquet or .csv). Parquet recommended.",
89
95
  )
90
96
  @click.option("--tournament", "-t", default="equities", help="Tournament (equities/futures)")
91
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
97
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
92
98
  def submit(model: str, file_path: str, tournament: str, api_key: str | None) -> None:
93
99
  """Submit predictions from a Parquet or CSV file.
94
100
 
@@ -102,7 +108,9 @@ def submit(model: str, file_path: str, tournament: str, api_key: str | None) ->
102
108
  try:
103
109
  if ext == "parquet":
104
110
  result = api.submit_predictions_file(
105
- model_name=model, file_path=file_path, tournament=tournament,
111
+ model_name=model,
112
+ file_path=file_path,
113
+ tournament=tournament,
106
114
  )
107
115
  elif ext == "csv":
108
116
  import csv as _csv
@@ -115,8 +123,7 @@ def submit(model: str, file_path: str, tournament: str, api_key: str | None) ->
115
123
  result = api.submit_futures_predictions(model_id=model, predictions=preds)
116
124
  else:
117
125
  preds_list = [
118
- {"ticker": row["ticker"], "score": float(row["score"])}
119
- for row in rows
126
+ {"ticker": row["ticker"], "score": float(row["score"])} for row in rows
120
127
  ]
121
128
  result = api.submit_predictions(model_id=model, predictions=preds_list)
122
129
  else:
@@ -135,7 +142,7 @@ def submit(model: str, file_path: str, tournament: str, api_key: str | None) ->
135
142
  @cli.command()
136
143
  @click.option("--period", "-p", default="30d", help="Period (7d/30d/90d/all)")
137
144
  @click.option("--tournament", "-t", default="equities", help="Tournament (equities/futures)")
138
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
145
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
139
146
  def leaderboard(period: str, tournament: str, api_key: str | None) -> None:
140
147
  """Show tournament leaderboard."""
141
148
  api = _get_api(api_key)
@@ -153,7 +160,7 @@ def leaderboard(period: str, tournament: str, api_key: str | None) -> None:
153
160
  @cli.command()
154
161
  @click.option("--model", "-m", required=True, help="Model identifier")
155
162
  @click.option("--days", "-d", default=30, help="Look-back window")
156
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
163
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
157
164
  def scores(model: str, days: int, api_key: str | None) -> None:
158
165
  """Show scoring results for a model."""
159
166
  api = _get_api(api_key)
@@ -166,7 +173,7 @@ def scores(model: str, days: int, api_key: str | None) -> None:
166
173
 
167
174
  @cli.command()
168
175
  @click.option("--model", "-m", required=True, help="Model identifier")
169
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
176
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
170
177
  def diagnostics(model: str, api_key: str | None) -> None:
171
178
  """Show per-round diagnostics for a model."""
172
179
  api = _get_api(api_key)
@@ -180,7 +187,7 @@ def diagnostics(model: str, api_key: str | None) -> None:
180
187
  @cli.command()
181
188
  @click.option("--tournament", "-t", default="equities", help="Tournament (equities/futures)")
182
189
  @click.option("--limit", "-n", default=10, help="Number of rounds")
183
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
190
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
184
191
  def rounds(tournament: str, limit: int, api_key: str | None) -> None:
185
192
  """List tournament rounds."""
186
193
  api = _get_api(api_key)
@@ -192,7 +199,7 @@ def rounds(tournament: str, limit: int, api_key: str | None) -> None:
192
199
 
193
200
 
194
201
  @cli.command()
195
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
202
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
196
203
  def credits(api_key: str | None) -> None:
197
204
  """Check compute credit balance."""
198
205
  api = _get_api(api_key)
@@ -205,7 +212,7 @@ def credits(api_key: str | None) -> None:
205
212
 
206
213
  @cli.command()
207
214
  @click.option("--model", "-m", required=True, help="Model identifier")
208
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
215
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
209
216
  def stake_balance(model: str, api_key: str | None) -> None:
210
217
  """Show stake balance and pending payouts."""
211
218
  api = _get_api(api_key)
@@ -227,15 +234,15 @@ def register(name: str, email: str) -> None:
227
234
  click.echo("Registration successful!")
228
235
  click.echo(f" Agent ID: {result['agent_id']}")
229
236
  click.echo(f" API Key: {result['api_key']} (save this — shown once)")
230
- click.echo(f"\nSet your API key:")
231
- click.echo(f" export EVEREST_API_KEY={result['api_key']}")
237
+ click.echo("\nSet your API key:")
238
+ click.echo(f" export EIQ_API_KEY={result['api_key']}")
232
239
  except EverestError as e:
233
240
  click.echo(f"Error: {e}", err=True)
234
241
  sys.exit(1)
235
242
 
236
243
 
237
244
  @cli.command()
238
- @click.option("--api-key", envvar="EVEREST_API_KEY", default=None)
245
+ @click.option("--api-key", envvar=["EIQ_API_KEY", "EVEREST_API_KEY"], default=None)
239
246
  def universe(api_key: str | None) -> None:
240
247
  """Show current tournament universe."""
241
248
  api = _get_api(api_key)
@@ -86,6 +86,7 @@ def _open_no_symlink(path: str):
86
86
  st = None
87
87
  if st is not None:
88
88
  import stat as _stat
89
+
89
90
  if _stat.S_ISLNK(st.st_mode):
90
91
  raise OSError(
91
92
  f"Refusing to write to symlink at {path!r} (symlink-following blocked)",
@@ -108,9 +109,9 @@ class EverestAPI:
108
109
  Parameters
109
110
  ----------
110
111
  api_key : str, optional
111
- EverestQuant API key. Falls back to ``EVEREST_API_KEY`` env var.
112
+ EverestQuant API key. Falls back to ``EIQ_API_KEY`` (or legacy ``EVEREST_API_KEY``) env var.
112
113
  base_url : str, optional
113
- Base URL for the API. Defaults to ``https://everestquant.ai`` (apex
114
+ Base URL for the API. Defaults to ``https://everesteer.ai`` (apex
114
115
  domain), overridable via ``EVEREST_API_URL`` env var.
115
116
  timeout : float
116
117
  HTTP timeout in seconds.
@@ -124,7 +125,7 @@ class EverestAPI:
124
125
  explicitly supplied.
125
126
  """
126
127
 
127
- DEFAULT_BASE_URL = os.getenv("EVEREST_API_URL", "https://everestquant.ai")
128
+ DEFAULT_BASE_URL = os.getenv("EVEREST_API_URL", "https://everesteer.ai")
128
129
 
129
130
  def __init__(
130
131
  self,
@@ -136,7 +137,7 @@ class EverestAPI:
136
137
  cf_access_client_id: str | None = None,
137
138
  cf_access_client_secret: str | None = None,
138
139
  ) -> None:
139
- self.api_key = api_key or os.getenv("EVEREST_API_KEY", "")
140
+ self.api_key = api_key or os.getenv("EIQ_API_KEY") or os.getenv("EVEREST_API_KEY", "")
140
141
  self.base_url = (base_url or self.DEFAULT_BASE_URL).rstrip("/")
141
142
  self.tournament = tournament
142
143
 
@@ -307,7 +308,9 @@ class EverestAPI:
307
308
  return self.get_validation_panel(model_id=model_id, days=days)
308
309
 
309
310
  def get_model_per_exped_breakdown(
310
- self, model_id: str, days: int = 3650,
311
+ self,
312
+ model_id: str,
313
+ days: int = 3650,
311
314
  ) -> list[float]:
312
315
  """Return the per-exped CORR series for a model (oldest→newest).
313
316
 
@@ -317,7 +320,10 @@ class EverestAPI:
317
320
  return list(resp.get("per_exped_corr", []))
318
321
 
319
322
  def get_job_output(
320
- self, job_id: str, filename: str, output_path: str | None = None,
323
+ self,
324
+ job_id: str,
325
+ filename: str,
326
+ output_path: str | None = None,
321
327
  ) -> str:
322
328
  """Download an output file from a completed compute job.
323
329
 
@@ -332,7 +338,8 @@ class EverestAPI:
332
338
  # like "../etc/passwd" can't escape cwd.
333
339
  output_path = _safe_output_path(filename, server_supplied=True)
334
340
  return self._download(
335
- f"/api/v1/compute/jobs/{job_id}/output/{filename}", output_path,
341
+ f"/api/v1/compute/jobs/{job_id}/output/{filename}",
342
+ output_path,
336
343
  )
337
344
 
338
345
  def get_scores(self, model_id: str, days: int = 30) -> dict:
@@ -443,8 +450,7 @@ class EverestAPI:
443
450
  "model_id": model_id,
444
451
  "exped": exped or "current",
445
452
  "predictions": [
446
- {"instrument_id": iid, "prediction": pred}
447
- for iid, pred in predictions.items()
453
+ {"instrument_id": iid, "prediction": pred} for iid, pred in predictions.items()
448
454
  ],
449
455
  }
450
456
  return self._request("POST", "/api/v1/futures/submit/v2", json=body)
@@ -460,10 +466,7 @@ class EverestAPI:
460
466
  .. deprecated::
461
467
  Use :meth:`submit_futures_predictions` (v2) instead.
462
468
  """
463
- preds_list = [
464
- {"instrument_id": k, "targets": v}
465
- for k, v in sorted(predictions.items())
466
- ]
469
+ preds_list = [{"instrument_id": k, "targets": v} for k, v in sorted(predictions.items())]
467
470
  body = {"model_id": model_id, "exped": exped, "predictions": preds_list}
468
471
  return self._request("POST", "/api/v1/futures/submit", json=body)
469
472
 
@@ -511,7 +514,8 @@ class EverestAPI:
511
514
  if version in (None, "latest", "current"):
512
515
  version = self._current_dataset_version(universe) or "v0"
513
516
  return self._download(
514
- f"/api/v1/data/{version}/benchmark/{universe}/{split}", output_path,
517
+ f"/api/v1/data/{version}/benchmark/{universe}/{split}",
518
+ output_path,
515
519
  )
516
520
 
517
521
  def download_ai_model(
@@ -524,7 +528,8 @@ class EverestAPI:
524
528
  if output_path is None:
525
529
  output_path = f"ai_model_{universe}.parquet"
526
530
  return self._download(
527
- f"/api/v1/data/{version}/ai-model/{universe}", output_path,
531
+ f"/api/v1/data/{version}/ai-model/{universe}",
532
+ output_path,
528
533
  )
529
534
 
530
535
  # -- compute ----------------------------------------------------------
@@ -539,7 +544,9 @@ class EverestAPI:
539
544
  ) -> dict:
540
545
  """Submit Tier 1 serverless training job."""
541
546
  body: dict = {
542
- "model": model, "features": features, "target": target,
547
+ "model": model,
548
+ "features": features,
549
+ "target": target,
543
550
  "universe": universe,
544
551
  }
545
552
  if params:
@@ -599,6 +606,7 @@ class EverestAPI:
599
606
  def wait_for_job(self, job_id: str, timeout: int = 3600) -> dict:
600
607
  """Block until job completes. Exponential backoff polling."""
601
608
  import time
609
+
602
610
  delay = 2.0
603
611
  elapsed = 0.0
604
612
  while elapsed < timeout:
@@ -676,15 +684,24 @@ class EverestAPI:
676
684
 
677
685
  def get_rounds(self, tournament: str = "equities", limit: int = 25) -> dict:
678
686
  """GET /api/v1/rounds — list tournament rounds."""
679
- return self._request("GET", "/api/v1/rounds", params={
680
- "tournament": tournament, "limit": str(limit),
681
- })
687
+ return self._request(
688
+ "GET",
689
+ "/api/v1/rounds",
690
+ params={
691
+ "tournament": tournament,
692
+ "limit": str(limit),
693
+ },
694
+ )
682
695
 
683
696
  def get_current_round(self, tournament: str = "equities") -> dict:
684
697
  """GET /api/v1/rounds/current — current active round."""
685
- return self._request("GET", "/api/v1/rounds/current", params={
686
- "tournament": tournament,
687
- })
698
+ return self._request(
699
+ "GET",
700
+ "/api/v1/rounds/current",
701
+ params={
702
+ "tournament": tournament,
703
+ },
704
+ )
688
705
 
689
706
  def get_schedule(self) -> dict:
690
707
  """GET /api/v1/schedule — round schedule for both tournaments."""
@@ -715,9 +732,14 @@ class EverestAPI:
715
732
 
716
733
  def set_multipliers(self, model_id: str, corr_mult: float, aimc_mult: float) -> dict:
717
734
  """PATCH /api/v1/models/{model_id}/multipliers — set payout multipliers."""
718
- return self._request("PATCH", f"/api/v1/models/{model_id}/multipliers", json={
719
- "corr_multiplier": corr_mult, "aimc_multiplier": aimc_mult,
720
- })
735
+ return self._request(
736
+ "PATCH",
737
+ f"/api/v1/models/{model_id}/multipliers",
738
+ json={
739
+ "corr_multiplier": corr_mult,
740
+ "aimc_multiplier": aimc_mult,
741
+ },
742
+ )
721
743
 
722
744
  def get_multipliers(self, model_id: str) -> dict:
723
745
  """GET /api/v1/models/{model_id}/multipliers"""
@@ -741,17 +763,26 @@ class EverestAPI:
741
763
 
742
764
  def stake(self, model_id: str, amount_usdc: float, wallet_address: str) -> dict:
743
765
  """Stake USDC on a model."""
744
- return self._request("POST", "/api/v1/staking/stake", json={
745
- "model_id": model_id,
746
- "amount_usdc": amount_usdc,
747
- "wallet_address": wallet_address,
748
- })
766
+ return self._request(
767
+ "POST",
768
+ "/api/v1/staking/stake",
769
+ json={
770
+ "model_id": model_id,
771
+ "amount_usdc": amount_usdc,
772
+ "wallet_address": wallet_address,
773
+ },
774
+ )
749
775
 
750
776
  def confirm_stake(self, stake_id: str, txn_hash: str) -> dict:
751
777
  """Confirm a stake with on-chain transaction hash."""
752
- return self._request("POST", "/api/v1/staking/confirm", json={
753
- "stake_id": stake_id, "txn_hash": txn_hash,
754
- })
778
+ return self._request(
779
+ "POST",
780
+ "/api/v1/staking/confirm",
781
+ json={
782
+ "stake_id": stake_id,
783
+ "txn_hash": txn_hash,
784
+ },
785
+ )
755
786
 
756
787
  def unstake(self, stake_id: str) -> dict:
757
788
  """Unstake USDC from a model."""
@@ -763,9 +794,14 @@ class EverestAPI:
763
794
 
764
795
  def claim_payout(self, model_id: str, round_id: str) -> dict:
765
796
  """Claim resolved payout for a model and round."""
766
- return self._request("POST", "/api/v1/staking/claim", json={
767
- "model_id": model_id, "round_id": round_id,
768
- })
797
+ return self._request(
798
+ "POST",
799
+ "/api/v1/staking/claim",
800
+ json={
801
+ "model_id": model_id,
802
+ "round_id": round_id,
803
+ },
804
+ )
769
805
 
770
806
  def get_staking_history(self, model_id: str) -> dict:
771
807
  """Get stake/unstake/claim history."""
@@ -787,9 +823,14 @@ class EverestAPI:
787
823
 
788
824
  def withdraw_usdc(self, to_address: str, amount_usdc: float) -> dict:
789
825
  """Withdraw USDC to external wallet."""
790
- return self._request("POST", "/api/v1/staking/withdraw", json={
791
- "to_address": to_address, "amount_usdc": amount_usdc,
792
- })
826
+ return self._request(
827
+ "POST",
828
+ "/api/v1/staking/withdraw",
829
+ json={
830
+ "to_address": to_address,
831
+ "amount_usdc": amount_usdc,
832
+ },
833
+ )
793
834
 
794
835
  def get_forwarder_balance(self) -> dict:
795
836
  """GET /api/v1/staking/forwarder-balance"""
@@ -836,13 +877,13 @@ class EverestAPI:
836
877
 
837
878
  @staticmethod
838
879
  def evaluate(
839
- predictions: "np.ndarray | pd.Series",
840
- validation_data: "pd.DataFrame",
880
+ predictions: np.ndarray | pd.Series,
881
+ validation_data: pd.DataFrame,
841
882
  target: str = "target_everest_20",
842
883
  ) -> dict:
843
884
  """Evaluate predictions against validation set locally."""
844
885
  import numpy as np
845
- from scipy.stats import spearmanr, rankdata
886
+ from scipy.stats import rankdata, spearmanr
846
887
 
847
888
  preds = np.asarray(predictions)
848
889
  targets = validation_data[target].values
@@ -864,8 +905,8 @@ class EverestAPI:
864
905
  pd_dev = pred_ranks - pm
865
906
  td_dev = target_ranks - tm
866
907
  cov = np.dot(weights, pd_dev * td_dev) / w_sum
867
- pvar = np.dot(weights, pd_dev ** 2) / w_sum
868
- tvar = np.dot(weights, td_dev ** 2) / w_sum
908
+ pvar = np.dot(weights, pd_dev**2) / w_sum
909
+ tvar = np.dot(weights, td_dev**2) / w_sum
869
910
  denom = np.sqrt(pvar * tvar)
870
911
  result["weighted_corr"] = round(float(cov / denom), 6) if denom > 0 else 0.0
871
912
  else:
@@ -10,8 +10,8 @@ Run::
10
10
  python -m everestapi.mcp
11
11
 
12
12
  Requires environment variables:
13
- EVEREST_API_KEY — your EverestQuant API key (also accepts EIQ_API_KEY)
14
- EIQ_BASE_URL — API base URL (default: https://everestquant.ai)
13
+ EIQ_API_KEY — your EverestQuant API key (also accepts legacy EVEREST_API_KEY)
14
+ EIQ_BASE_URL — API base URL (default: https://everesteer.ai)
15
15
  CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET — Cloudflare Access service
16
16
  token, required only when the host sits behind CF Access (e.g. staging)
17
17
  """
@@ -47,7 +47,7 @@ _client = None
47
47
  def _get_client():
48
48
  """Lazily build (and cache) the EverestAPI SDK client.
49
49
 
50
- Reads ``EVEREST_API_KEY`` (or ``EIQ_API_KEY``) and ``EIQ_BASE_URL`` (or
50
+ Reads ``EIQ_API_KEY`` (or legacy ``EVEREST_API_KEY``) and ``EIQ_BASE_URL`` (or
51
51
  ``EVEREST_API_URL``) from the environment. Cloudflare Access service tokens
52
52
  (``CF_ACCESS_CLIENT_ID`` / ``CF_ACCESS_CLIENT_SECRET``) are honoured by the
53
53
  EverestAPI constructor, so a host behind CF Access (e.g. staging) works
@@ -57,14 +57,14 @@ def _get_client():
57
57
  if _client is None:
58
58
  from everestapi import EverestAPI
59
59
 
60
- api_key = os.environ.get("EVEREST_API_KEY") or os.environ.get("EIQ_API_KEY", "")
60
+ api_key = os.environ.get("EIQ_API_KEY") or os.environ.get("EVEREST_API_KEY", "")
61
61
  base_url = (
62
62
  os.environ.get("EIQ_BASE_URL")
63
63
  or os.environ.get("EVEREST_API_URL")
64
- or "https://everestquant.ai"
64
+ or "https://everesteer.ai"
65
65
  )
66
66
  if not api_key:
67
- raise RuntimeError("EVEREST_API_KEY environment variable is required")
67
+ raise RuntimeError("EIQ_API_KEY environment variable is required")
68
68
  # EverestAPI reads CF_ACCESS_CLIENT_ID/SECRET from the environment in its
69
69
  # own constructor, so staging (behind Cloudflare Access) works with no
70
70
  # extra wiring here.
@@ -189,7 +189,11 @@ TOOLS = [
189
189
  "inputSchema": {
190
190
  "type": "object",
191
191
  "properties": {
192
- "version": {"type": "string", "description": "Dataset version (default: bregen)", "default": "bregen"},
192
+ "version": {
193
+ "type": "string",
194
+ "description": "Dataset version (default: bregen)",
195
+ "default": "bregen",
196
+ },
193
197
  },
194
198
  "required": [],
195
199
  },
@@ -201,7 +205,10 @@ TOOLS = [
201
205
  "type": "object",
202
206
  "properties": {
203
207
  "universe": {"type": "string", "description": "Universe: 'futures' or 'equities'"},
204
- "split": {"type": "string", "description": "Split: 'train', 'validation', or 'live'"},
208
+ "split": {
209
+ "type": "string",
210
+ "description": "Split: 'train', 'validation', or 'live'",
211
+ },
205
212
  "output_path": {"type": "string", "description": "Local path to save (optional)"},
206
213
  },
207
214
  "required": ["universe", "split"],
@@ -214,7 +221,11 @@ TOOLS = [
214
221
  "type": "object",
215
222
  "properties": {
216
223
  "universe": {"type": "string", "default": "futures"},
217
- "split": {"type": "string", "default": "validation", "description": "'validation' or 'live'"},
224
+ "split": {
225
+ "type": "string",
226
+ "default": "validation",
227
+ "description": "'validation' or 'live'",
228
+ },
218
229
  "output_path": {"type": "string", "description": "Local path (optional)"},
219
230
  },
220
231
  "required": [],
@@ -227,8 +238,16 @@ TOOLS = [
227
238
  "type": "object",
228
239
  "properties": {
229
240
  "model": {"type": "string", "enum": ["lightgbm", "xgboost", "ridge", "mlp"]},
230
- "features": {"type": "string", "enum": ["small", "medium", "all"], "default": "small"},
231
- "target": {"type": "string", "default": "target_everest_20", "description": "Target column. Futures payout uses target_everest_20 (20-day forward return). Multiple target types available. See get_dataset_schema for full list."},
241
+ "features": {
242
+ "type": "string",
243
+ "enum": ["small", "medium", "all"],
244
+ "default": "small",
245
+ },
246
+ "target": {
247
+ "type": "string",
248
+ "default": "target_everest_20",
249
+ "description": "Target column. Futures payout uses target_everest_20 (20-day forward return). Multiple target types available. See get_dataset_schema for full list.",
250
+ },
232
251
  "universe": {"type": "string", "default": "futures"},
233
252
  "params": {"type": "object", "description": "Model hyperparameters (optional)"},
234
253
  },
@@ -255,7 +274,10 @@ TOOLS = [
255
274
  "inputSchema": {
256
275
  "type": "object",
257
276
  "properties": {
258
- "job_id": {"type": "string", "description": "Job ID from quick_train or custom_train"},
277
+ "job_id": {
278
+ "type": "string",
279
+ "description": "Job ID from quick_train or custom_train",
280
+ },
259
281
  },
260
282
  "required": ["job_id"],
261
283
  },
@@ -266,7 +288,10 @@ TOOLS = [
266
288
  "inputSchema": {
267
289
  "type": "object",
268
290
  "properties": {
269
- "job_id": {"type": "string", "description": "Job ID from quick_train or custom_train"},
291
+ "job_id": {
292
+ "type": "string",
293
+ "description": "Job ID from quick_train or custom_train",
294
+ },
270
295
  },
271
296
  "required": ["job_id"],
272
297
  },
@@ -286,8 +311,16 @@ TOOLS = [
286
311
  "inputSchema": {
287
312
  "type": "object",
288
313
  "properties": {
289
- "tournament": {"type": "string", "description": "Tournament: 'equities' or 'futures'", "default": "equities"},
290
- "limit": {"type": "integer", "description": "Max rounds to return (default 25)", "default": 25},
314
+ "tournament": {
315
+ "type": "string",
316
+ "description": "Tournament: 'equities' or 'futures'",
317
+ "default": "equities",
318
+ },
319
+ "limit": {
320
+ "type": "integer",
321
+ "description": "Max rounds to return (default 25)",
322
+ "default": 25,
323
+ },
291
324
  },
292
325
  "required": [],
293
326
  },
@@ -298,7 +331,11 @@ TOOLS = [
298
331
  "inputSchema": {
299
332
  "type": "object",
300
333
  "properties": {
301
- "tournament": {"type": "string", "description": "Tournament: 'equities' or 'futures'", "default": "equities"},
334
+ "tournament": {
335
+ "type": "string",
336
+ "description": "Tournament: 'equities' or 'futures'",
337
+ "default": "equities",
338
+ },
302
339
  },
303
340
  "required": [],
304
341
  },
@@ -341,8 +378,14 @@ TOOLS = [
341
378
  "inputSchema": {
342
379
  "type": "object",
343
380
  "properties": {
344
- "name": {"type": "string", "description": "Model name (this becomes the model_id for submit/upload)."},
345
- "description": {"type": "string", "description": "Optional human-readable description."},
381
+ "name": {
382
+ "type": "string",
383
+ "description": "Model name (this becomes the model_id for submit/upload).",
384
+ },
385
+ "description": {
386
+ "type": "string",
387
+ "description": "Optional human-readable description.",
388
+ },
346
389
  },
347
390
  "required": ["name"],
348
391
  },
@@ -383,7 +426,11 @@ TOOLS = [
383
426
  "type": "object",
384
427
  "properties": {
385
428
  "model_id": {"type": "string", "description": "Model to run diagnostics on"},
386
- "days": {"type": "integer", "description": "Number of days of history (default 365)", "default": 365},
429
+ "days": {
430
+ "type": "integer",
431
+ "description": "Number of days of history (default 365)",
432
+ "default": 365,
433
+ },
387
434
  },
388
435
  "required": ["model_id"],
389
436
  },
@@ -413,7 +460,11 @@ TOOLS = [
413
460
  "type": "object",
414
461
  "properties": {
415
462
  "model_id": {"type": "string", "description": "Model to query"},
416
- "days": {"type": "integer", "description": "History window in days (default 3650 = full tournament history)", "default": 3650},
463
+ "days": {
464
+ "type": "integer",
465
+ "description": "History window in days (default 3650 = full tournament history)",
466
+ "default": 3650,
467
+ },
417
468
  },
418
469
  "required": ["model_id"],
419
470
  },
@@ -426,7 +477,10 @@ TOOLS = [
426
477
  "properties": {
427
478
  "model_id": {"type": "string", "description": "Model to stake on."},
428
479
  "amount_usdc": {"type": "number", "description": "Amount of USDC to stake."},
429
- "wallet_address": {"type": "string", "description": "On-chain wallet address holding the USDC."},
480
+ "wallet_address": {
481
+ "type": "string",
482
+ "description": "On-chain wallet address holding the USDC.",
483
+ },
430
484
  },
431
485
  "required": ["model_id", "amount_usdc", "wallet_address"],
432
486
  },
@@ -437,7 +491,10 @@ TOOLS = [
437
491
  "inputSchema": {
438
492
  "type": "object",
439
493
  "properties": {
440
- "stake_id": {"type": "string", "description": "Stake ID returned by stake_on_model."},
494
+ "stake_id": {
495
+ "type": "string",
496
+ "description": "Stake ID returned by stake_on_model.",
497
+ },
441
498
  },
442
499
  "required": ["stake_id"],
443
500
  },
@@ -460,7 +517,10 @@ TOOLS = [
460
517
  "type": "object",
461
518
  "properties": {
462
519
  "model_id": {"type": "string", "description": "Model identifier."},
463
- "round_id": {"type": "string", "description": "Round identifier for the payout to claim."},
520
+ "round_id": {
521
+ "type": "string",
522
+ "description": "Round identifier for the payout to claim.",
523
+ },
464
524
  },
465
525
  "required": ["model_id", "round_id"],
466
526
  },
@@ -503,7 +563,10 @@ TOOLS = [
503
563
  "inputSchema": {
504
564
  "type": "object",
505
565
  "properties": {
506
- "round_id": {"type": "integer", "description": "Round identifier for the payout to claim."},
566
+ "round_id": {
567
+ "type": "integer",
568
+ "description": "Round identifier for the payout to claim.",
569
+ },
507
570
  },
508
571
  "required": ["round_id"],
509
572
  },
@@ -729,6 +792,7 @@ def _dispatch(name: str, arguments: dict) -> str:
729
792
  # MCP-SDK path (preferred)
730
793
  # ===================================================================
731
794
 
795
+
732
796
  def _build_mcp_server() -> Server:
733
797
  """Build and return a configured MCP Server instance."""
734
798
  server = Server("eiq-mcp")
@@ -769,6 +833,7 @@ async def _run_mcp() -> None:
769
833
  # Fallback: minimal JSON-RPC 2.0 over stdin/stdout
770
834
  # ===================================================================
771
835
 
836
+
772
837
  def _run_jsonrpc_fallback() -> None:
773
838
  """Minimal JSON-RPC 2.0 loop for environments without the ``mcp`` package."""
774
839
  import sys
@@ -790,11 +855,14 @@ def _run_jsonrpc_fallback() -> None:
790
855
  params = req.get("params", {})
791
856
 
792
857
  if method == "initialize":
793
- _jsonrpc_respond(req_id, result={
794
- "protocolVersion": "2024-11-05",
795
- "capabilities": {"tools": {"listChanged": False}},
796
- "serverInfo": {"name": "eiq-mcp", "version": "0.1.0"},
797
- })
858
+ _jsonrpc_respond(
859
+ req_id,
860
+ result={
861
+ "protocolVersion": "2024-11-05",
862
+ "capabilities": {"tools": {"listChanged": False}},
863
+ "serverInfo": {"name": "eiq-mcp", "version": "0.1.0"},
864
+ },
865
+ )
798
866
  elif method == "tools/list":
799
867
  _jsonrpc_respond(req_id, result={"tools": TOOLS})
800
868
  elif method == "tools/call":
@@ -802,14 +870,20 @@ def _run_jsonrpc_fallback() -> None:
802
870
  arguments = params.get("arguments", {})
803
871
  try:
804
872
  text = _dispatch(tool_name, arguments)
805
- _jsonrpc_respond(req_id, result={
806
- "content": [{"type": "text", "text": text}],
807
- })
873
+ _jsonrpc_respond(
874
+ req_id,
875
+ result={
876
+ "content": [{"type": "text", "text": text}],
877
+ },
878
+ )
808
879
  except Exception as exc:
809
- _jsonrpc_respond(req_id, result={
810
- "content": [{"type": "text", "text": json.dumps({"error": str(exc)})}],
811
- "isError": True,
812
- })
880
+ _jsonrpc_respond(
881
+ req_id,
882
+ result={
883
+ "content": [{"type": "text", "text": json.dumps({"error": str(exc)})}],
884
+ "isError": True,
885
+ },
886
+ )
813
887
  elif method == "notifications/initialized":
814
888
  pass # no response needed for notifications
815
889
  else:
@@ -831,10 +905,12 @@ def _jsonrpc_respond(req_id, *, result=None, error=None) -> None:
831
905
  # Entry point
832
906
  # ===================================================================
833
907
 
908
+
834
909
  def main() -> None:
835
910
  """Run the MCP server over stdio (the transport Claude Code / Cursor use)."""
836
911
  if _HAS_MCP:
837
912
  import asyncio
913
+
838
914
  asyncio.run(_run_mcp())
839
915
  else:
840
916
  _run_jsonrpc_fallback()
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: everestapi
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Python SDK for the EverestQuant prediction tournament platform
5
- Author-email: EverestQuant <engineering@everestquant.ai>
5
+ Author-email: EverestQuant <support@everesteer.ai>
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://everestquant.ai
8
- Project-URL: Documentation, https://docs.everestquant.ai
7
+ Project-URL: Homepage, https://everesteer.ai
8
+ Project-URL: Documentation, https://docs.everesteer.ai
9
9
  Project-URL: Repository, https://github.com/everestquant/everestapi-public
10
10
  Keywords: quant,tournament,prediction,staking,machine-learning
11
11
  Classifier: Development Status :: 4 - Beta
@@ -30,7 +30,7 @@ Dynamic: license-file
30
30
 
31
31
  # everestapi
32
32
 
33
- Python SDK for the [EverestQuant](https://everestquant.ai) prediction tournament platform.
33
+ Python SDK for the [EverestQuant](https://everesteer.ai) prediction tournament platform.
34
34
 
35
35
  ```bash
36
36
  pip install everestapi
@@ -59,7 +59,7 @@ api.submit_futures_predictions(
59
59
  scores = api.get_scores(model_id="my-model", days=30)
60
60
  ```
61
61
 
62
- Or set `EVEREST_API_KEY` as an environment variable and omit the constructor argument.
62
+ Or set `EIQ_API_KEY` as an environment variable and omit the constructor argument.
63
63
 
64
64
  > **Handling your API key.** Shell history, terminal recordings, and CI logs may persist any value you `echo` or `print`. Copy the key via the clipboard rather than echoing it in a recorded session, and prefer storing it in a secrets manager or `.env` file (gitignored) over inlining in source.
65
65
 
@@ -17,6 +17,7 @@ from everestapi.cli import cli
17
17
  def runner(monkeypatch):
18
18
  monkeypatch.setattr("everestapi.client.EverestAPI.DEFAULT_BASE_URL", "http://test")
19
19
  monkeypatch.setenv("EVEREST_API_KEY", "eiq_test_key")
20
+ monkeypatch.delenv("EIQ_API_KEY", raising=False)
20
21
  monkeypatch.delenv("EIQ_BASIC_AUTH_USER", raising=False)
21
22
  monkeypatch.delenv("EIQ_BASIC_AUTH_PASS", raising=False)
22
23
  return CliRunner()
@@ -16,6 +16,7 @@ from everestapi import EverestAPI, EverestError
16
16
  def api(monkeypatch):
17
17
  for var in (
18
18
  "EVEREST_API_URL",
19
+ "EIQ_API_KEY",
19
20
  "EVEREST_API_KEY",
20
21
  "EIQ_BASIC_AUTH_USER",
21
22
  "EIQ_BASIC_AUTH_PASS",
@@ -31,6 +32,7 @@ def test_api_key_header_set(httpx_mock, api):
31
32
 
32
33
 
33
34
  def test_empty_api_key_omits_header(httpx_mock, monkeypatch):
35
+ monkeypatch.delenv("EIQ_API_KEY", raising=False)
34
36
  monkeypatch.delenv("EVEREST_API_KEY", raising=False)
35
37
  client = EverestAPI(base_url="http://test")
36
38
  httpx_mock.add_response(url="http://test/api/v1/health", json={"status": "ok"})
@@ -122,8 +124,9 @@ def test_cf_service_token_kwargs_override_env(monkeypatch):
122
124
  monkeypatch.setenv("CF_ACCESS_CLIENT_ID", "env.access")
123
125
  monkeypatch.setenv("CF_ACCESS_CLIENT_SECRET", "envv")
124
126
  kid, ksec = "kw.access", "kwv"
125
- client = EverestAPI(api_key=_K, base_url=_URL,
126
- cf_access_client_id=kid, cf_access_client_secret=ksec)
127
+ client = EverestAPI(
128
+ api_key=_K, base_url=_URL, cf_access_client_id=kid, cf_access_client_secret=ksec
129
+ )
127
130
  h = client._client.headers
128
131
  assert h["cf-access-client-id"] == kid
129
132
  assert h["cf-access-client-secret"] == ksec
@@ -14,6 +14,7 @@ from everestapi import EverestAPI, EverestError
14
14
  def api(monkeypatch):
15
15
  for var in (
16
16
  "EVEREST_API_URL",
17
+ "EIQ_API_KEY",
17
18
  "EVEREST_API_KEY",
18
19
  "CF_ACCESS_CLIENT_ID",
19
20
  "CF_ACCESS_CLIENT_SECRET",
@@ -26,30 +27,37 @@ def api(monkeypatch):
26
27
 
27
28
  # -- client: model management --------------------------------------------
28
29
 
30
+
29
31
  def test_create_model_posts_body(httpx_mock, api):
30
32
  httpx_mock.add_response(
31
- url="http://test/api/v1/agents/me/models", method="POST",
33
+ url="http://test/api/v1/agents/me/models",
34
+ method="POST",
32
35
  json={"id": "m1", "name": "my-model"},
33
36
  )
34
37
  out = api.create_model("my-model", description="d")
35
38
  assert out["name"] == "my-model"
36
39
  assert json.loads(httpx_mock.get_request().content) == {
37
- "name": "my-model", "description": "d",
40
+ "name": "my-model",
41
+ "description": "d",
38
42
  }
39
43
 
40
44
 
41
45
  def test_create_model_idempotent_on_409(httpx_mock, api):
42
46
  httpx_mock.add_response(
43
- url="http://test/api/v1/agents/me/models", method="POST",
44
- status_code=409, json={"detail": "exists"},
47
+ url="http://test/api/v1/agents/me/models",
48
+ method="POST",
49
+ status_code=409,
50
+ json={"detail": "exists"},
45
51
  )
46
52
  assert api.create_model("dup") == {"name": "dup", "status": "already_exists"}
47
53
 
48
54
 
49
55
  def test_create_model_reraises_non_409(httpx_mock, api):
50
56
  httpx_mock.add_response(
51
- url="http://test/api/v1/agents/me/models", method="POST",
52
- status_code=400, json={"detail": "bad"},
57
+ url="http://test/api/v1/agents/me/models",
58
+ method="POST",
59
+ status_code=400,
60
+ json={"detail": "bad"},
53
61
  )
54
62
  with pytest.raises(EverestError):
55
63
  api.create_model("x")
@@ -57,7 +65,8 @@ def test_create_model_reraises_non_409(httpx_mock, api):
57
65
 
58
66
  def test_get_models(httpx_mock, api):
59
67
  httpx_mock.add_response(
60
- url="http://test/api/v1/agents/me/models", method="GET",
68
+ url="http://test/api/v1/agents/me/models",
69
+ method="GET",
61
70
  json={"agent_id": "a", "models": []},
62
71
  )
63
72
  assert api.get_models()["models"] == []
@@ -65,13 +74,16 @@ def test_get_models(httpx_mock, api):
65
74
 
66
75
  # -- client: versioned dataset download (the #558 fix) -------------------
67
76
 
77
+
68
78
  def test_download_dataset_uses_versioned_route(httpx_mock, api, tmp_path):
69
79
  httpx_mock.add_response(
70
80
  url="http://test/api/v1/data/download/bregen/futures/train",
71
81
  content=b"PAR1data",
72
82
  )
73
83
  out = api.download_dataset(
74
- universe="futures", split="train", version="bregen",
84
+ universe="futures",
85
+ split="train",
86
+ version="bregen",
75
87
  output_path=str(tmp_path / "t.parquet"),
76
88
  )
77
89
  assert httpx_mock.get_request().url.path == "/api/v1/data/download/bregen/futures/train"
@@ -89,7 +101,9 @@ def test_download_dataset_latest_resolves_version(httpx_mock, api, tmp_path):
89
101
  content=b"PAR1live",
90
102
  )
91
103
  out = api.download_dataset(
92
- universe="futures", split="live", version="latest",
104
+ universe="futures",
105
+ split="live",
106
+ version="latest",
93
107
  output_path=str(tmp_path / "l.parquet"),
94
108
  )
95
109
  with open(out, "rb") as f:
@@ -98,12 +112,18 @@ def test_download_dataset_latest_resolves_version(httpx_mock, api, tmp_path):
98
112
 
99
113
  # -- MCP server -----------------------------------------------------------
100
114
 
115
+
101
116
  def test_mcp_tools_include_loop_and_model_tools():
102
117
  from everestapi.mcp import server
118
+
103
119
  names = {t["name"] for t in server.TOOLS}
104
120
  for needed in (
105
- "download_dataset", "create_model", "get_models",
106
- "submit_futures_predictions", "get_current_round", "get_scores",
121
+ "download_dataset",
122
+ "create_model",
123
+ "get_models",
124
+ "submit_futures_predictions",
125
+ "get_current_round",
126
+ "get_scores",
107
127
  ):
108
128
  assert needed in names, needed
109
129
 
File without changes
File without changes