diff --git a/llama_stack/cli/download.py b/llama_stack/cli/download.py index b43d50217..f1b722183 100644 --- a/llama_stack/cli/download.py +++ b/llama_stack/cli/download.py @@ -10,7 +10,7 @@ import json import os import shutil from dataclasses import dataclass -from datetime import datetime +from datetime import datetime, timezone from functools import partial from pathlib import Path from typing import Dict, List, Optional @@ -404,7 +404,7 @@ def _download_from_manifest(manifest_file: str, max_concurrent_downloads: int): d = json.load(f) manifest = Manifest(**d) - if datetime.now() > manifest.expires_on: + if datetime.now(timezone.utc) > manifest.expires_on: raise ValueError(f"Manifest URLs have expired on {manifest.expires_on}") console = Console() diff --git a/llama_stack/models/llama/llama3/prompt_templates/system_prompts.py b/llama_stack/models/llama/llama3/prompt_templates/system_prompts.py index 02e4814bc..b835d0ec0 100644 --- a/llama_stack/models/llama/llama3/prompt_templates/system_prompts.py +++ b/llama_stack/models/llama/llama3/prompt_templates/system_prompts.py @@ -34,7 +34,9 @@ class SystemDefaultGenerator(PromptTemplateGeneratorBase): ) return PromptTemplate( template_str.lstrip("\n"), - {"today": datetime.now().strftime("%d %B %Y")}, + { + "today": datetime.now().strftime("%d %B %Y") # noqa: DTZ005 - we don't care about timezones here since we are displaying the date + }, ) def data_examples(self) -> List[Any]: diff --git a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py index 0ae1996cc..03692bcc7 100644 --- a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py +++ b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py @@ -11,7 +11,7 @@ import re import secrets import string import uuid -from datetime import datetime +from datetime import datetime, timezone from typing import AsyncGenerator, List, Optional, Union from urllib.parse import urlparse @@ -239,7 +239,7 @@ class ChatAgent(ShieldRunnerMixin): in_progress_tool_call_step = await self.storage.get_in_progress_tool_call_step( request.session_id, request.turn_id ) - now = datetime.now().astimezone().isoformat() + now = datetime.now(timezone.utc).isoformat() tool_execution_step = ToolExecutionStep( step_id=(in_progress_tool_call_step.step_id if in_progress_tool_call_step else str(uuid.uuid4())), turn_id=request.turn_id, @@ -264,7 +264,7 @@ class ChatAgent(ShieldRunnerMixin): start_time = last_turn.started_at else: messages.extend(request.messages) - start_time = datetime.now().astimezone().isoformat() + start_time = datetime.now(timezone.utc).isoformat() input_messages = request.messages output_message = None @@ -295,7 +295,7 @@ class ChatAgent(ShieldRunnerMixin): input_messages=input_messages, output_message=output_message, started_at=start_time, - completed_at=datetime.now().astimezone().isoformat(), + completed_at=datetime.now(timezone.utc).isoformat(), steps=steps, ) await self.storage.add_turn_to_session(request.session_id, turn) @@ -386,7 +386,7 @@ class ChatAgent(ShieldRunnerMixin): return step_id = str(uuid.uuid4()) - shield_call_start_time = datetime.now().astimezone().isoformat() + shield_call_start_time = datetime.now(timezone.utc).isoformat() try: yield AgentTurnResponseStreamChunk( event=AgentTurnResponseEvent( @@ -410,7 +410,7 @@ class ChatAgent(ShieldRunnerMixin): turn_id=turn_id, violation=e.violation, started_at=shield_call_start_time, - completed_at=datetime.now().astimezone().isoformat(), + completed_at=datetime.now(timezone.utc).isoformat(), ), ) ) @@ -433,7 +433,7 @@ class ChatAgent(ShieldRunnerMixin): turn_id=turn_id, violation=None, started_at=shield_call_start_time, - completed_at=datetime.now().astimezone().isoformat(), + completed_at=datetime.now(timezone.utc).isoformat(), ), ) ) @@ -472,7 +472,7 @@ class ChatAgent(ShieldRunnerMixin): client_tools[tool.name] = tool while True: step_id = str(uuid.uuid4()) - inference_start_time = datetime.now().astimezone().isoformat() + inference_start_time = datetime.now(timezone.utc).isoformat() yield AgentTurnResponseStreamChunk( event=AgentTurnResponseEvent( payload=AgentTurnResponseStepStartPayload( @@ -582,7 +582,7 @@ class ChatAgent(ShieldRunnerMixin): turn_id=turn_id, model_response=copy.deepcopy(message), started_at=inference_start_time, - completed_at=datetime.now().astimezone().isoformat(), + completed_at=datetime.now(timezone.utc).isoformat(), ), ) ) @@ -653,7 +653,7 @@ class ChatAgent(ShieldRunnerMixin): turn_id=turn_id, tool_calls=[tool_call], tool_responses=[], - started_at=datetime.now().astimezone().isoformat(), + started_at=datetime.now(timezone.utc).isoformat(), ), ) yield message @@ -670,7 +670,7 @@ class ChatAgent(ShieldRunnerMixin): "input": message.model_dump_json(), }, ) as span: - tool_execution_start_time = datetime.now().astimezone().isoformat() + tool_execution_start_time = datetime.now(timezone.utc).isoformat() tool_call = message.tool_calls[0] tool_result = await self.execute_tool_call_maybe( session_id, @@ -708,7 +708,7 @@ class ChatAgent(ShieldRunnerMixin): ) ], started_at=tool_execution_start_time, - completed_at=datetime.now().astimezone().isoformat(), + completed_at=datetime.now(timezone.utc).isoformat(), ), ) ) diff --git a/llama_stack/providers/inline/agents/meta_reference/persistence.py b/llama_stack/providers/inline/agents/meta_reference/persistence.py index 2c04305fd..e7d7d1828 100644 --- a/llama_stack/providers/inline/agents/meta_reference/persistence.py +++ b/llama_stack/providers/inline/agents/meta_reference/persistence.py @@ -7,7 +7,7 @@ import json import logging import uuid -from datetime import datetime +from datetime import datetime, timezone from typing import List, Optional from pydantic import BaseModel @@ -36,7 +36,7 @@ class AgentPersistence: session_info = AgentSessionInfo( session_id=session_id, session_name=name, - started_at=datetime.now(), + started_at=datetime.now(timezone.utc), ) await self.kvstore.set( key=f"session:{self.agent_id}:{session_id}", diff --git a/llama_stack/providers/inline/post_training/torchtune/post_training.py b/llama_stack/providers/inline/post_training/torchtune/post_training.py index 3a1affc91..2c129ef41 100644 --- a/llama_stack/providers/inline/post_training/torchtune/post_training.py +++ b/llama_stack/providers/inline/post_training/torchtune/post_training.py @@ -3,7 +3,7 @@ # # This source code is licensed under the terms described in the LICENSE file in # the root directory of this source tree. -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Dict, Optional from llama_stack.apis.datasetio import DatasetIO @@ -64,7 +64,7 @@ class TorchtunePostTrainingImpl: job_status_response = PostTrainingJobStatusResponse( job_uuid=job_uuid, status=JobStatus.scheduled, - scheduled_at=datetime.now(), + scheduled_at=datetime.now(timezone.utc), ) self.jobs[job_uuid] = job_status_response @@ -84,7 +84,7 @@ class TorchtunePostTrainingImpl: ) job_status_response.status = JobStatus.in_progress - job_status_response.started_at = datetime.now() + job_status_response.started_at = datetime.now(timezone.utc) await recipe.setup() resources_allocated, checkpoints = await recipe.train() @@ -93,7 +93,7 @@ class TorchtunePostTrainingImpl: job_status_response.resources_allocated = resources_allocated job_status_response.checkpoints = checkpoints job_status_response.status = JobStatus.completed - job_status_response.completed_at = datetime.now() + job_status_response.completed_at = datetime.now(timezone.utc) except Exception: job_status_response.status = JobStatus.failed diff --git a/llama_stack/providers/inline/post_training/torchtune/recipes/lora_finetuning_single_device.py b/llama_stack/providers/inline/post_training/torchtune/recipes/lora_finetuning_single_device.py index c88787f18..941c629e3 100644 --- a/llama_stack/providers/inline/post_training/torchtune/recipes/lora_finetuning_single_device.py +++ b/llama_stack/providers/inline/post_training/torchtune/recipes/lora_finetuning_single_device.py @@ -8,7 +8,7 @@ import gc import logging import os import time -from datetime import datetime +from datetime import datetime, timezone from functools import partial from pathlib import Path from typing import Any, Dict, List, Optional, Tuple @@ -532,7 +532,7 @@ class LoraFinetuningSingleDevice: checkpoint_path = await self.save_checkpoint(epoch=curr_epoch) checkpoint = Checkpoint( identifier=f"{self.model_id}-sft-{curr_epoch}", - created_at=datetime.now(), + created_at=datetime.now(timezone.utc), epoch=curr_epoch, post_training_job_id=self.job_uuid, path=checkpoint_path, diff --git a/llama_stack/providers/inline/telemetry/meta_reference/console_span_processor.py b/llama_stack/providers/inline/telemetry/meta_reference/console_span_processor.py index 2e3bd4d3a..42b538876 100644 --- a/llama_stack/providers/inline/telemetry/meta_reference/console_span_processor.py +++ b/llama_stack/providers/inline/telemetry/meta_reference/console_span_processor.py @@ -5,7 +5,7 @@ # the root directory of this source tree. import json -from datetime import datetime +from datetime import datetime, timezone from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.sdk.trace.export import SpanProcessor @@ -34,7 +34,7 @@ class ConsoleSpanProcessor(SpanProcessor): if span.attributes and span.attributes.get("__autotraced__"): return - timestamp = datetime.utcfromtimestamp(span.start_time / 1e9).strftime("%H:%M:%S.%f")[:-3] + timestamp = datetime.fromtimestamp(span.start_time / 1e9, tz=timezone.utc).strftime("%H:%M:%S.%f")[:-3] print( f"{COLORS['dim']}{timestamp}{COLORS['reset']} " @@ -46,7 +46,7 @@ class ConsoleSpanProcessor(SpanProcessor): if span.attributes and span.attributes.get("__autotraced__"): return - timestamp = datetime.utcfromtimestamp(span.end_time / 1e9).strftime("%H:%M:%S.%f")[:-3] + timestamp = datetime.fromtimestamp(span.end_time / 1e9, tz=timezone.utc).strftime("%H:%M:%S.%f")[:-3] span_context = ( f"{COLORS['dim']}{timestamp}{COLORS['reset']} " @@ -74,7 +74,7 @@ class ConsoleSpanProcessor(SpanProcessor): print(f" {COLORS['dim']}{key}: {str_value}{COLORS['reset']}") for event in span.events: - event_time = datetime.utcfromtimestamp(event.timestamp / 1e9).strftime("%H:%M:%S.%f")[:-3] + event_time = datetime.fromtimestamp(event.timestamp / 1e9, tz=timezone.utc).strftime("%H:%M:%S.%f")[:-3] severity = event.attributes.get("severity", "info") message = event.attributes.get("message", event.name) diff --git a/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py b/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py index b39ee7716..5ed586fce 100644 --- a/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py +++ b/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py @@ -8,7 +8,7 @@ import json import os import sqlite3 import threading -from datetime import datetime +from datetime import datetime, timezone from opentelemetry.sdk.trace import SpanProcessor from opentelemetry.trace import Span @@ -124,8 +124,8 @@ class SQLiteSpanProcessor(SpanProcessor): trace_id, service_name, (span_id if not parent_span_id else None), - datetime.fromtimestamp(span.start_time / 1e9).isoformat(), - datetime.fromtimestamp(span.end_time / 1e9).isoformat(), + datetime.fromtimestamp(span.start_time / 1e9, timezone.utc).isoformat(), + datetime.fromtimestamp(span.end_time / 1e9, timezone.utc).isoformat(), ), ) @@ -143,8 +143,8 @@ class SQLiteSpanProcessor(SpanProcessor): trace_id, parent_span_id, span.name, - datetime.fromtimestamp(span.start_time / 1e9).isoformat(), - datetime.fromtimestamp(span.end_time / 1e9).isoformat(), + datetime.fromtimestamp(span.start_time / 1e9, timezone.utc).isoformat(), + datetime.fromtimestamp(span.end_time / 1e9, timezone.utc).isoformat(), json.dumps(dict(span.attributes)), span.status.status_code.name, span.kind.name, @@ -161,7 +161,7 @@ class SQLiteSpanProcessor(SpanProcessor): ( span_id, event.name, - datetime.fromtimestamp(event.timestamp / 1e9).isoformat(), + datetime.fromtimestamp(event.timestamp / 1e9, timezone.utc).isoformat(), json.dumps(dict(event.attributes)), ), ) diff --git a/llama_stack/providers/inline/tool_runtime/code_interpreter/code_execution.py b/llama_stack/providers/inline/tool_runtime/code_interpreter/code_execution.py index d7b2dbdef..810591c1c 100644 --- a/llama_stack/providers/inline/tool_runtime/code_interpreter/code_execution.py +++ b/llama_stack/providers/inline/tool_runtime/code_interpreter/code_execution.py @@ -168,7 +168,7 @@ def process_matplotlib_response(response, matplotlib_dump_dir: str): image_paths = [] for i, img in enumerate(images): # create new directory for each day to better organize data: - dump_dname = datetime.today().strftime("%Y-%m-%d") + dump_dname = datetime.today().strftime("%Y-%m-%d") # noqa: DTZ002 - we don't care about timezones here since we are displaying the date dump_dpath = Path(matplotlib_dump_dir, dump_dname) dump_dpath.mkdir(parents=True, exist_ok=True) # save image into a file diff --git a/llama_stack/providers/utils/telemetry/tracing.py b/llama_stack/providers/utils/telemetry/tracing.py index bef229080..607d1a918 100644 --- a/llama_stack/providers/utils/telemetry/tracing.py +++ b/llama_stack/providers/utils/telemetry/tracing.py @@ -11,7 +11,7 @@ import logging import queue import threading import uuid -from datetime import datetime +from datetime import datetime, timezone from functools import wraps from typing import Any, Callable, Dict, List, Optional @@ -86,7 +86,7 @@ class TraceContext: span_id=generate_short_uuid(), trace_id=self.trace_id, name=name, - start_time=datetime.now(), + start_time=datetime.now(timezone.utc), parent_span_id=current_span.span_id if current_span else None, attributes=attributes, ) @@ -203,7 +203,7 @@ class TelemetryHandler(logging.Handler): UnstructuredLogEvent( trace_id=span.trace_id, span_id=span.span_id, - timestamp=datetime.now(), + timestamp=datetime.now(timezone.utc), message=self.format(record), severity=severity(record.levelname), ) diff --git a/pyproject.toml b/pyproject.toml index aaea4f7c4..ff7f46f77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,14 +124,15 @@ exclude = [ [tool.ruff.lint] select = [ - "B", # flake8-bugbear - "B9", # flake8-bugbear subset - "C", # comprehensions - "E", # pycodestyle - "F", # Pyflakes - "N", # Naming - "W", # Warnings - "I", # isort + "B", # flake8-bugbear + "B9", # flake8-bugbear subset + "C", # comprehensions + "E", # pycodestyle + "F", # Pyflakes + "N", # Naming + "W", # Warnings + "I", # isort + "DTZ", # datetime rules ] ignore = [ # The following ignores are desired by the project maintainers. @@ -145,6 +146,10 @@ ignore = [ "C901", # Complexity of the function is too high ] +# Ignore the following errors for the following files +[tool.ruff.lint.per-file-ignores] +"tests/**/*.py" = ["DTZ"] # Ignore datetime rules for tests + [tool.mypy] mypy_path = ["llama_stack"] packages = ["llama_stack"]