mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
Fix CI: guard starlette imports, asyncio.run(), deprecate datetime.utcnow()
- Guard starlette imports in test_compress_api.py (skip ASGI tests without proxy deps) - Replace asyncio.get_event_loop().run_until_complete() with asyncio.run() (Python 3.13) - Replace datetime.utcnow() with datetime.now(timezone.utc).replace(tzinfo=None) everywhere
This commit is contained in:
parent
0a434531d8
commit
0adc39ab7a
10 changed files with 41 additions and 33 deletions
|
|
@ -6,7 +6,7 @@ import asyncio
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ def _get_stats(store: SQLiteMemoryStore) -> dict[str, Any]:
|
|||
stats["by_scope"] = by_scope
|
||||
|
||||
# Count by age buckets
|
||||
now = datetime.utcnow()
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
by_age: dict[str, int] = {}
|
||||
|
||||
one_day_ago = (now - timedelta(days=1)).isoformat()
|
||||
|
|
@ -302,7 +302,7 @@ def list_memories(
|
|||
|
||||
if since_duration:
|
||||
duration = parse_duration(since_duration)
|
||||
cutoff = datetime.utcnow() - duration
|
||||
cutoff = datetime.now(timezone.utc).replace(tzinfo=None) - duration
|
||||
filter_kwargs["created_after"] = cutoff
|
||||
|
||||
mem_filter = MemoryFilter(**filter_kwargs)
|
||||
|
|
@ -692,7 +692,7 @@ def prune_memories(
|
|||
|
||||
if older_than:
|
||||
duration = parse_duration(older_than)
|
||||
cutoff = datetime.utcnow() - duration
|
||||
cutoff = datetime.now(timezone.utc).replace(tzinfo=None) - duration
|
||||
filter_kwargs["created_before"] = cutoff
|
||||
|
||||
if scope:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterator
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from .cache import (
|
||||
|
|
@ -388,7 +388,7 @@ class HeadroomClient:
|
|||
) -> Any:
|
||||
"""Internal implementation of create."""
|
||||
request_id = generate_request_id()
|
||||
timestamp = datetime.utcnow()
|
||||
timestamp = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
mode = HeadroomMode(headroom_mode) if headroom_mode else self._default_mode
|
||||
|
||||
tokenizer = self._get_tokenizer(model)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from __future__ import annotations
|
|||
import json
|
||||
import re
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
|
@ -606,7 +606,7 @@ class SQLiteMemoryStore:
|
|||
ValueError: If the old memory is not found.
|
||||
"""
|
||||
if supersede_time is None:
|
||||
supersede_time = datetime.utcnow()
|
||||
supersede_time = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
# Get the old memory
|
||||
old_memory = await self.get(old_memory_id)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from __future__ import annotations
|
|||
import asyncio
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from headroom.memory.models import Memory
|
||||
|
|
@ -217,10 +217,18 @@ class Mem0Backend:
|
|||
|
||||
# Parse timestamps
|
||||
created_at_str = metadata.get("created_at")
|
||||
created_at = datetime.fromisoformat(created_at_str) if created_at_str else datetime.utcnow()
|
||||
created_at = (
|
||||
datetime.fromisoformat(created_at_str)
|
||||
if created_at_str
|
||||
else datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
)
|
||||
|
||||
valid_from_str = metadata.get("valid_from")
|
||||
valid_from = datetime.fromisoformat(valid_from_str) if valid_from_str else datetime.utcnow()
|
||||
valid_from = (
|
||||
datetime.fromisoformat(valid_from_str)
|
||||
if valid_from_str
|
||||
else datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
)
|
||||
|
||||
valid_until_str = metadata.get("valid_until")
|
||||
valid_until = datetime.fromisoformat(valid_until_str) if valid_until_str else None
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import hashlib
|
|||
import json
|
||||
import re
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
# Marker format for Headroom modifications
|
||||
|
|
@ -69,7 +69,7 @@ def compute_prefix_hash(messages: list[dict[str, Any]], prefix_count: int | None
|
|||
def format_timestamp(dt: datetime | None = None) -> str:
|
||||
"""Format datetime as ISO8601 string."""
|
||||
if dt is None:
|
||||
dt = datetime.utcnow()
|
||||
dt = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
return dt.isoformat() + "Z"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -231,9 +231,7 @@ class TestLiteLLMCallback:
|
|||
],
|
||||
}
|
||||
|
||||
result = asyncio.get_event_loop().run_until_complete(
|
||||
callback.async_pre_call_hook("key", data, "completion")
|
||||
)
|
||||
result = asyncio.run(callback.async_pre_call_hook("key", data, "completion"))
|
||||
assert result is data
|
||||
|
||||
def test_callback_ignores_non_completion(self):
|
||||
|
|
@ -245,7 +243,5 @@ class TestLiteLLMCallback:
|
|||
callback = HeadroomCallback()
|
||||
data = {"messages": [{"role": "user", "content": "hi"}]}
|
||||
|
||||
result = asyncio.get_event_loop().run_until_complete(
|
||||
callback.async_pre_call_hook("key", data, "embedding")
|
||||
)
|
||||
result = asyncio.run(callback.async_pre_call_hook("key", data, "embedding"))
|
||||
assert result is data
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ This module provides JWT-based authentication with role-based access control.
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from typing import Optional, List, Any
|
||||
|
||||
import jwt
|
||||
|
|
@ -181,16 +181,16 @@ def create_access_token(
|
|||
>>> print(token) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
"""
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
expire = datetime.now(timezone.utc).replace(tzinfo=None) + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=TOKEN_EXPIRE_MINUTES)
|
||||
expire = datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(minutes=TOKEN_EXPIRE_MINUTES)
|
||||
|
||||
payload = {
|
||||
"sub": user_id,
|
||||
"exp": expire,
|
||||
"roles": roles or [],
|
||||
"permissions": permissions or [],
|
||||
"iat": datetime.utcnow(),
|
||||
"iat": datetime.now(timezone.utc).replace(tzinfo=None),
|
||||
}
|
||||
|
||||
encoded_jwt = jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
|
||||
|
|
@ -313,7 +313,7 @@ class RateLimiter:
|
|||
Returns:
|
||||
True if request is allowed, False if rate limited.
|
||||
"""
|
||||
now = datetime.utcnow()
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
cutoff = now - timedelta(seconds=self.window_size)
|
||||
|
||||
# Clean old entries
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ PRODUCT_CATALOG = json.dumps(
|
|||
|
||||
CODE_FILE = '''"""User authentication service with JWT tokens."""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from typing import Optional
|
||||
import jwt
|
||||
from pydantic import BaseModel
|
||||
|
|
@ -155,9 +155,9 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -
|
|||
"""
|
||||
to_encode = data.copy()
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
expire = datetime.now(timezone.utc).replace(tzinfo=None) + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
expire = datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
|
@ -215,7 +215,7 @@ class RateLimiter:
|
|||
|
||||
def is_allowed(self, client_id: str) -> bool:
|
||||
"""Check if a request from client_id is allowed."""
|
||||
now = datetime.utcnow()
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
cutoff = now - timedelta(seconds=self.window_seconds)
|
||||
|
||||
if client_id not in self._requests:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|||
|
||||
import asyncio
|
||||
import tempfile
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
|
@ -113,7 +113,11 @@ class TestMemoryModel:
|
|||
current = Memory(content="test", user_id="alice")
|
||||
assert current.is_current is True
|
||||
|
||||
superseded = Memory(content="test", user_id="alice", valid_until=datetime.utcnow())
|
||||
superseded = Memory(
|
||||
content="test",
|
||||
user_id="alice",
|
||||
valid_until=datetime.now(timezone.utc).replace(tzinfo=None),
|
||||
)
|
||||
assert superseded.is_current is False
|
||||
|
||||
def test_memory_serialization(self, sample_embedding):
|
||||
|
|
@ -555,7 +559,7 @@ class TestIntegration:
|
|||
|
||||
# Supersede
|
||||
new_memory = Memory(content="New preference", user_id="alice")
|
||||
supersede_time = datetime.utcnow()
|
||||
supersede_time = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
await store.supersede(original.id, new_memory, supersede_time)
|
||||
|
||||
# Query at a point when original was valid (after its valid_from, before supersession)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import os
|
|||
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
||||
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
|
@ -960,7 +960,7 @@ class MockBackend:
|
|||
)
|
||||
self._memories[new_memory.id] = new_memory
|
||||
old_memory.superseded_by = new_memory.id
|
||||
old_memory.valid_until = datetime.utcnow()
|
||||
old_memory.valid_until = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
return new_memory
|
||||
|
||||
async def delete_memory(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue