simulacrum-sdk 0.2.2__tar.gz → 0.2.3__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.

Potentially problematic release.


This version of simulacrum-sdk might be problematic. Click here for more details.

Files changed (20) hide show
  1. {simulacrum_sdk-0.2.2/simulacrum_sdk.egg-info → simulacrum_sdk-0.2.3}/PKG-INFO +1 -1
  2. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/pyproject.toml +1 -1
  3. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/client.py +3 -1
  4. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/models.py +19 -2
  5. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3/simulacrum_sdk.egg-info}/PKG-INFO +1 -1
  6. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/tests/test_client.py +10 -5
  7. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/tests/test_errors.py +5 -0
  8. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/LICENSE +0 -0
  9. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/MANIFEST.in +0 -0
  10. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/README.md +0 -0
  11. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/setup.cfg +0 -0
  12. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/__init__.py +0 -0
  13. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/_errors.py +0 -0
  14. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/api.py +0 -0
  15. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/config.py +0 -0
  16. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum/exceptions.py +0 -0
  17. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum_sdk.egg-info/SOURCES.txt +0 -0
  18. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum_sdk.egg-info/dependency_links.txt +0 -0
  19. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum_sdk.egg-info/requires.txt +0 -0
  20. {simulacrum_sdk-0.2.2 → simulacrum_sdk-0.2.3}/simulacrum_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulacrum-sdk
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Official Python SDK for accessing the Simulacrum API.
5
5
  Author-email: "Simulacrum, Inc." <support@smlcrm.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simulacrum-sdk"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Official Python SDK for accessing the Simulacrum API."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -41,7 +41,7 @@ class Simulacrum:
41
41
  }
42
42
 
43
43
  def forecast(
44
- self, series: Sequence[float] | np.ndarray, horizon: int, model: str = "default"
44
+ self, series: Sequence[float] | np.ndarray, horizon: int | None = None, model: str = "default"
45
45
  ) -> np.ndarray:
46
46
  """Request a forecast for the provided time series.
47
47
 
@@ -86,6 +86,8 @@ class Simulacrum:
86
86
  series=series_to_send, horizon=horizon, model=model
87
87
  )
88
88
  request_body: Dict[str, Any] = payload.model_dump()
89
+ # Exclude optional fields that are None (e.g., horizon for onsiteiq)
90
+ request_body = payload.model_dump(exclude_none=True)
89
91
  response_data: Dict[str, Any] = send_request(
90
92
  method="POST",
91
93
  url=f"{self.base_url}/{model}/v1/forecast",
@@ -12,7 +12,7 @@ class ForecastRequest(BaseModel):
12
12
 
13
13
  Attributes:
14
14
  series (list[float]): Historical observations used as forecast input.
15
- horizon (int): Number of future periods to predict.
15
+ horizon (int | None): Number of future periods to predict. Optional for the ``"onsiteiq"`` model.
16
16
  model (str | None): Identifier of the forecasting model, defaults to ``"default"``.
17
17
 
18
18
  Example:
@@ -23,7 +23,7 @@ class ForecastRequest(BaseModel):
23
23
  """
24
24
 
25
25
  series: List[float]
26
- horizon: int
26
+ horizon: Optional[int] = None
27
27
  model: Optional[str] = "default"
28
28
 
29
29
  @field_validator("series", mode="before")
@@ -41,6 +41,23 @@ class ForecastRequest(BaseModel):
41
41
  return value.astype(float).tolist()
42
42
  return list(value)
43
43
 
44
+ @model_validator(mode="after")
45
+ def _validate_horizon_requirement(self):
46
+ # Horizon is required for all models except onsiteiq
47
+ model_name = (self.model or "").lower()
48
+ if model_name != "onsiteiq" and self.horizon is None:
49
+ raise ValueError("horizon is required and must be a positive integer for this model")
50
+
51
+ # When provided, horizon must be an integer >= 1
52
+ if self.horizon is not None:
53
+ if not isinstance(self.horizon, int):
54
+ raise ValueError(
55
+ f"horizon must be an integer (got {type(self.horizon).__name__})"
56
+ )
57
+ if self.horizon < 1:
58
+ raise ValueError("horizon must be >= 1")
59
+ return self
60
+
44
61
 
45
62
  class ForecastResponse(BaseModel):
46
63
  """Forecast output returned by the API.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulacrum-sdk
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Official Python SDK for accessing the Simulacrum API.
5
5
  Author-email: "Simulacrum, Inc." <support@smlcrm.com>
6
6
  License-Expression: MIT
@@ -1,4 +1,8 @@
1
1
  import os
2
+ import sys
3
+
4
+ # Ensure package import works when running tests directly
5
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
2
6
  import pytest
3
7
  import numpy as np
4
8
 
@@ -9,12 +13,13 @@ import simulacrum.client as simulacrum_client
9
13
 
10
14
  @pytest.fixture
11
15
  def client():
12
- base_url = os.environ.get("TEST_API")
13
- return simulacrum_client.Simulacrum(os.environ.get("TEST_API_KEY"), base_url=base_url)
16
+ base_url = os.environ["TEST_API"]
17
+ api_key = os.environ["TEST_KEY"]
18
+ return simulacrum_client.Simulacrum(api_key, base_url=base_url)
14
19
 
15
20
 
16
21
  def test_client_initializes_expected_headers(client):
17
- assert client.headers["Authorization"] == f"Bearer {os.environ.get('TEST_API_KEY')}"
22
+ assert client.headers["Authorization"] == f"Bearer {client.api_key}"
18
23
  assert client.headers["Content-Type"] == "application/json"
19
24
 
20
25
 
@@ -57,7 +62,7 @@ def test_forecast_builds_payload_and_returns_numpy_array(client, monkeypatch):
57
62
  captured_payload["horizon"] = horizon
58
63
  captured_payload["model"] = model
59
64
 
60
- def model_dump(self):
65
+ def model_dump(self, *args, **kwargs):
61
66
  return {
62
67
  "series": captured_payload["series"],
63
68
  "horizon": captured_payload["horizon"],
@@ -85,7 +90,7 @@ def test_forecast_builds_payload_and_returns_numpy_array(client, monkeypatch):
85
90
  assert captured_payload["horizon"] == 2
86
91
  assert captured_payload["model"] == "prophet"
87
92
  assert captured_payload["method"] == "POST"
88
- assert captured_payload["url"] == "https://api.test/prophet/v1/forecast"
93
+ assert captured_payload["url"] == f"{client.base_url}/prophet/v1/forecast"
89
94
  assert captured_payload["headers"] == client.headers
90
95
  assert captured_payload["json"] == {
91
96
  "series": [1.0, 2.0, 3.0],
@@ -1,4 +1,9 @@
1
1
  import json
2
+ import os
3
+ import sys
4
+
5
+ # Ensure package import works when running tests directly
6
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
2
7
  from datetime import datetime, timedelta, timezone
3
8
 
4
9
  from simulacrum._errors import parse_error
File without changes
File without changes
File without changes