Skip to content

Commit 7fc7b4e

Browse files
authored
Merge branch 'main' into feat/categorical_features
2 parents 85976b2 + f191403 commit 7fc7b4e

File tree

6 files changed

+294
-153
lines changed

6 files changed

+294
-153
lines changed

.github/workflows/pytest.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,19 @@ jobs:
5656
run: >
5757
make devenv
5858
59+
- name: Cleanup old finetuned models
60+
run: >
61+
uv run python scripts/cleanup_finetuned_models.py --older-than 60
62+
continue-on-error: true
63+
5964
- name: Run tests (Linux Python 3.11)
6065
if: runner.os == 'Linux' && matrix.python-version == '3.11'
6166
env:
6267
# Required for distributed tests: Ray/Spark spawn worker processes
6368
# that need to locate the correct Python environment
6469
UV_PROJECT_ENVIRONMENT: ${{ github.workspace }}/.venv
65-
run: uv run pytest --cov=nixtla --reruns 3 --reruns-delay 10 --only-rerun ConnectError --only-rerun "Too Many Requests" nixtla_tests
70+
run: uv run pytest --cov=nixtla --reruns 3 --reruns-delay 10 --only-rerun ConnectError --only-rerun "Too Many Requests" --only-rerun "Internal server error" nixtla_tests
6671

6772
- name: Run tests (not Linux Python 3.11)
6873
if: runner.os != 'Linux' || matrix.python-version != '3.11'
69-
run: uv run pytest --cov=nixtla -m "not distributed_run" --reruns 3 --reruns-delay 10 --only-rerun ConnectError --only-rerun "Too Many Requests" nixtla_tests
74+
run: uv run pytest --cov=nixtla -m "not distributed_run" --reruns 3 --reruns-delay 10 --only-rerun ConnectError --only-rerun "Too Many Requests" --only-rerun "Internal server error" nixtla_tests

nixtla/nixtla_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ def __init__(
863863
if api_key is None:
864864
api_key = os.environ["NIXTLA_API_KEY"]
865865
if base_url is None:
866-
base_url = os.getenv("NIXTLA_BASE_URL", "https://api.nixtla.io")
866+
base_url = os.getenv("NIXTLA_BASE_URL") or "https://api.nixtla.io"
867867
self._client_kwargs = {
868868
"base_url": base_url,
869869
"headers": {

nixtla/scripts/snowflake_install_nixtla.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,17 @@ def package_and_upload_nixtla(
607607
# Detect package installer
608608
pip_cmd, use_uv = detect_package_installer()
609609

610+
# Clear pip cache to avoid corrupted or stale packages
611+
# This prevents zipfile.BadZipFile errors from overlapping entries
612+
cache_clear_cmd = (
613+
["uv", "cache", "clean"] if use_uv else ["pip", "cache", "purge"]
614+
)
615+
try:
616+
subprocess.run(cache_clear_cmd, check=False, capture_output=True)
617+
except Exception:
618+
# If cache clearing fails, continue anyway
619+
pass
620+
610621
# Build base install args (shared between PyPI and fallback attempts)
611622
base_args = pip_cmd + [
612623
"--target" if use_uv else "-t",

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ dev = [
7070
]
7171
distributed = [
7272
"fugue[dask,ray,spark]>=0.9.6",
73-
"dask<=2024.12.1",
73+
"dask",
7474
"pandas<2.2",
7575
"ray<=2.54.0",
7676
]
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Script to clean up finetuned models older than a specified duration.
5+
Usage: python scripts/cleanup_finetuned_models.py [--older-than MINUTES] [--dry-run]
6+
"""
7+
8+
import os
9+
import sys
10+
from argparse import ArgumentParser
11+
from datetime import datetime, timedelta, timezone
12+
13+
from nixtla.nixtla_client import NixtlaClient
14+
15+
16+
def cleanup_models(older_than_minutes: int = 30, dry_run: bool = False) -> int:
17+
"""
18+
Clean up finetuned models older than specified duration.
19+
20+
Args:
21+
older_than_minutes: Delete models older than this many minutes (default: 30).
22+
dry_run: If True, only list models without deleting them.
23+
24+
Returns:
25+
Number of models deleted.
26+
"""
27+
# Collect all credential pairs from environment
28+
credentials = [
29+
(os.environ.get("NIXTLA_API_KEY_CUSTOM"), os.environ.get("NIXTLA_BASE_URL_CUSTOM")),
30+
(os.environ.get("NIXTLA_API_KEY"), os.environ.get("NIXTLA_BASE_URL")),
31+
(os.environ.get("NIXTLA_API_KEY_FOR_SF"), os.environ.get("NIXTLA_BASE_URL")),
32+
]
33+
34+
# Filter out None/empty credentials
35+
credentials = [(key, url) for key, url in credentials if key and url]
36+
37+
if not credentials:
38+
print("[WARNING] No credentials found. Skipping cleanup.")
39+
return 0
40+
41+
now = datetime.now(timezone.utc)
42+
cutoff_time = now - timedelta(minutes=older_than_minutes)
43+
44+
total_deleted = 0
45+
total_failed = 0
46+
47+
for api_key, base_url in credentials:
48+
try:
49+
client = NixtlaClient(api_key=api_key, base_url=base_url)
50+
models = client.finetuned_models()
51+
except Exception:
52+
# Silently skip if unable to connect
53+
continue
54+
55+
# Filter models older than cutoff time
56+
old_models = []
57+
for model in models:
58+
model_time = model.created_at
59+
if model_time.tzinfo is None:
60+
model_time = model_time.replace(tzinfo=timezone.utc)
61+
62+
if model_time < cutoff_time:
63+
old_models.append(model)
64+
65+
if not old_models:
66+
continue
67+
68+
if dry_run:
69+
total_deleted += len(old_models)
70+
continue
71+
72+
# Delete old models
73+
for model in old_models:
74+
try:
75+
client.delete_finetuned_model(model.id)
76+
total_deleted += 1
77+
except Exception:
78+
total_failed += 1
79+
80+
if dry_run:
81+
print(f"[DRY RUN] Found {total_deleted} model(s) older than {older_than_minutes} minute(s)")
82+
print("[DRY RUN] Models would be deleted without --dry-run flag")
83+
else:
84+
print(f"[OK] Cleaned up {total_deleted} finetuned model(s)")
85+
if total_failed:
86+
print(f"[WARNING] {total_failed} model(s) failed to delete")
87+
88+
return total_deleted
89+
90+
91+
if __name__ == "__main__":
92+
parser = ArgumentParser(description="Clean up old finetuned models")
93+
parser.add_argument(
94+
"--older-than",
95+
type=int,
96+
default=30,
97+
help="Delete models older than this many minutes (default: 30)",
98+
)
99+
parser.add_argument("--dry-run", action="store_true", help="List models without deleting")
100+
args = parser.parse_args()
101+
102+
cleanup_models(older_than_minutes=args.older_than, dry_run=args.dry_run)
103+
sys.exit(0)

0 commit comments

Comments
 (0)