Skip to content

Commit 06d77a6

Browse files
committed
0.3.3 release
1 parent cb6d273 commit 06d77a6

File tree

15 files changed

+2485
-2430
lines changed

15 files changed

+2485
-2430
lines changed

.github/workflows/lint.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Lint
2+
3+
on:
4+
push:
5+
branches: [main, develop, feat/**]
6+
pull_request:
7+
branches: [main, develop]
8+
9+
jobs:
10+
ruff:
11+
name: Ruff (Linter & Formatter)
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: "3.11"
21+
22+
- name: Install Ruff
23+
run: pip install ruff
24+
25+
- name: Run Ruff linter
26+
run: ruff check faim_sdk/ faim_client/ tests/
27+
28+
- name: Run Ruff formatter check
29+
run: ruff format --check faim_sdk/ faim_client/ tests/
30+
31+
type-check:
32+
name: Type Checking (mypy)
33+
runs-on: ubuntu-latest
34+
steps:
35+
- name: Checkout code
36+
uses: actions/checkout@v4
37+
38+
- name: Set up Python
39+
uses: actions/setup-python@v5
40+
with:
41+
python-version: "3.11"
42+
43+
- name: Install uv
44+
uses: astral-sh/setup-uv@v3
45+
with:
46+
version: "latest"
47+
48+
- name: Install dependencies
49+
run: |
50+
uv pip install --system -e .
51+
uv pip install --system mypy types-requests
52+
53+
- name: Run mypy
54+
run: mypy faim_sdk/ --ignore-missing-imports --no-strict-optional
55+
continue-on-error: true
56+
57+
package-check:
58+
name: Package Build Check
59+
runs-on: ubuntu-latest
60+
steps:
61+
- name: Checkout code
62+
uses: actions/checkout@v4
63+
64+
- name: Set up Python
65+
uses: actions/setup-python@v5
66+
with:
67+
python-version: "3.11"
68+
69+
- name: Install build dependencies
70+
run: pip install poetry build twine
71+
72+
- name: Build package
73+
run: poetry build
74+
75+
- name: Check package with twine
76+
run: twine check dist/*
77+
78+
- name: Verify package contents
79+
run: |
80+
tar -tzf dist/*.tar.gz | grep -E "faim_sdk|faim_client"
81+
unzip -l dist/*.whl | grep -E "faim_sdk|faim_client"

.github/workflows/test.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [main, develop, feat/**]
6+
pull_request:
7+
branches: [main, develop]
8+
9+
jobs:
10+
test:
11+
name: Test Python ${{ matrix.python-version }}
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
python-version: ["3.11", "3.12"]
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Python ${{ matrix.python-version }}
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
27+
- name: Install uv
28+
uses: astral-sh/setup-uv@v3
29+
with:
30+
version: "latest"
31+
32+
- name: Install dependencies
33+
run: |
34+
uv pip install --system -e .
35+
uv pip install --system pytest pytest-cov pytest-asyncio
36+
37+
- name: Run unit tests
38+
run: |
39+
pytest tests/unit/ -v --cov=faim_sdk --cov=faim_client --cov-report=xml --cov-report=term
40+
41+
- name: Upload coverage to Codecov
42+
uses: codecov/codecov-action@v4
43+
if: matrix.python-version == '3.11'
44+
with:
45+
file: ./coverage.xml
46+
fail_ci_if_error: false
47+
token: ${{ secrets.CODECOV_TOKEN }}
48+
49+
test-examples:
50+
name: Test Examples
51+
runs-on: ubuntu-latest
52+
steps:
53+
- name: Checkout code
54+
uses: actions/checkout@v4
55+
56+
- name: Set up Python 3.11
57+
uses: actions/setup-python@v5
58+
with:
59+
python-version: "3.11"
60+
61+
- name: Install uv
62+
uses: astral-sh/setup-uv@v3
63+
with:
64+
version: "latest"
65+
66+
- name: Install dependencies with viz extras
67+
run: |
68+
uv pip install --system -e ".[viz]"
69+
uv pip install --system jupyterlab pandas statsmodels
70+
71+
- name: Check example notebooks can be read
72+
run: |
73+
python -c "import nbformat; nbformat.read('examples/flowstate_simple_example.ipynb', as_version=4)"
74+
python -c "import nbformat; nbformat.read('examples/model_comparison_example.ipynb', as_version=4)"
75+
76+
- name: Verify eval package imports
77+
run: |
78+
python -c "from faim_sdk.eval import mse, mase, crps_from_quantiles, plot_forecast; print('Eval imports successful')"

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ dmypy.json
2424

2525
openapi.json
2626
pyproject.toml
27-
CLAUDE.md
27+
CLAUDE.md
28+
/poetry.lock

README.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ pip install faim-sdk
2828
```python
2929
import numpy as np
3030
from faim_sdk import ForecastClient, Chronos2ForecastRequest
31-
from faim_client.models import ModelName
3231

3332
# Initialize client with your API endpoint
3433
client = ForecastClient(
@@ -49,8 +48,8 @@ request = Chronos2ForecastRequest(
4948
quantiles=[0.1, 0.5, 0.9] # 10th, 50th (median), 90th percentiles
5049
)
5150

52-
# Generate forecast
53-
response = client.forecast(ModelName.CHRONOS2, request)
51+
# Generate forecast - model inferred automatically from request type
52+
response = client.forecast(request)
5453

5554
# Access predictions
5655
print(response.quantiles.shape) # (32, 24, 3)
@@ -75,7 +74,7 @@ request = FlowStateForecastRequest(
7574
prediction_type="mean" # Options: "mean", "median"
7675
)
7776

78-
response = client.forecast(ModelName.FLOWSTATE, request)
77+
response = client.forecast(request)
7978
print(response.point.shape) # (batch_size, 24, features)
8079
```
8180

@@ -94,7 +93,7 @@ request = Chronos2ForecastRequest(
9493
quantiles=[0.05, 0.25, 0.5, 0.75, 0.95] # Full distribution
9594
)
9695

97-
response = client.forecast(ModelName.CHRONOS2, request)
96+
response = client.forecast(request)
9897
print(response.quantiles.shape) # (batch_size, 24, 5)
9998
```
10099

@@ -111,7 +110,7 @@ request = TiRexForecastRequest(
111110
output_type="point"
112111
)
113112

114-
response = client.forecast(ModelName.TIREX, request)
113+
response = client.forecast(request)
115114
print(response.point.shape) # (batch_size, 24, features)
116115
```
117116

@@ -120,7 +119,7 @@ print(response.point.shape) # (batch_size, 24, features)
120119
All forecasts return a `ForecastResponse` object with predictions and metadata:
121120

122121
```python
123-
response = client.forecast(ModelName.CHRONOS2, request)
122+
response = client.forecast(request)
124123

125124
# Access predictions based on output_type
126125
if response.point is not None:
@@ -252,7 +251,6 @@ fig, axes = plot_forecast(
252251
import numpy as np
253252
from faim_sdk import ForecastClient, Chronos2ForecastRequest
254253
from faim_sdk.eval import mse, mase, crps_from_quantiles, plot_forecast
255-
from faim_client.models import ModelName
256254

257255
# Initialize client
258256
client = ForecastClient(base_url="https://api.faim.example.com")
@@ -268,7 +266,7 @@ request = Chronos2ForecastRequest(
268266
output_type="quantiles",
269267
quantiles=[0.1, 0.5, 0.9]
270268
)
271-
response = client.forecast(ModelName.CHRONOS2, request)
269+
response = client.forecast(request)
272270

273271
# Evaluate point forecast (use median)
274272
point_pred = response.quantiles[:, :, 1:2] # Extract median, keep 3D shape
@@ -315,6 +313,7 @@ The SDK provides **machine-readable error codes** for robust error handling:
315313
```python
316314
from faim_sdk import (
317315
ForecastClient,
316+
Chronos2ForecastRequest,
318317
ValidationError,
319318
AuthenticationError,
320319
RateLimitError,
@@ -323,7 +322,8 @@ from faim_sdk import (
323322
)
324323

325324
try:
326-
response = client.forecast(ModelName.CHRONOS2, request)
325+
request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.5, 0.9])
326+
response = client.forecast(request)
327327

328328
except AuthenticationError as e:
329329
# Handle authentication failures (401, 403)
@@ -375,7 +375,6 @@ The SDK supports async operations for concurrent requests:
375375
```python
376376
import asyncio
377377
from faim_sdk import ForecastClient, Chronos2ForecastRequest
378-
from faim_client.models import ModelName
379378

380379
async def forecast_multiple_series():
381380
client = ForecastClient(
@@ -393,7 +392,7 @@ async def forecast_multiple_series():
393392
# Execute concurrently
394393
async with client:
395394
tasks = [
396-
client.forecast_async(ModelName.CHRONOS2, req)
395+
client.forecast_async(req)
397396
for req in requests
398397
]
399398
responses = await asyncio.gather(*tasks)
@@ -462,13 +461,15 @@ Use context managers for automatic resource cleanup:
462461
```python
463462
# Sync context manager
464463
with ForecastClient(base_url="https://api.faim.example.com") as client:
465-
response = client.forecast(ModelName.CHRONOS2, request)
464+
request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.5, 0.9])
465+
response = client.forecast(request)
466466
print(response.quantiles)
467467
# Client automatically closed
468468

469469
# Async context manager
470470
async with ForecastClient(base_url="https://api.faim.example.com") as client:
471-
response = await client.forecast_async(ModelName.CHRONOS2, request)
471+
request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.9])
472+
response = await client.forecast_async(request)
472473
print(response.quantiles)
473474
# Client automatically closed
474475
```

0 commit comments

Comments
 (0)