Fix Python 3.10 compatibility: Replace datetime.UTC with timezone.utc

- Created datetime_compat module to provide UTC constant using timezone.utc
- Updated all direct UTC imports to use compatibility module
- Added tests to verify UTC timezone compatibility
- Fixes #2171

Co-Authored-By: Joe Moura <joao@crewai.com>
This commit is contained in:
Devin AI
2025-02-20 01:50:08 +00:00
parent 00c2f5043e
commit c6ed4eaaf6
7 changed files with 37 additions and 10 deletions

View File

@@ -1,8 +1,7 @@
import ast
import datetime
import json
import time
from datetime import UTC
from datetime import datetime
from difflib import SequenceMatcher
from json import JSONDecodeError
from textwrap import dedent
@@ -18,6 +17,7 @@ from crewai.tools import BaseTool
from crewai.tools.structured_tool import CrewStructuredTool
from crewai.tools.tool_calling import InstructorToolCalling, ToolCalling
from crewai.utilities import I18N, Converter, ConverterError, Printer
from crewai.utilities.datetime_compat import UTC
from crewai.utilities.events.crewai_event_bus import crewai_event_bus
from crewai.utilities.events.tool_usage_events import (
ToolSelectionErrorEvent,
@@ -158,7 +158,7 @@ class ToolUsage:
self.task.increment_tools_errors()
started_at = time.time()
started_at_trace = datetime.datetime.now(UTC)
started_at_trace = datetime.now(UTC)
from_cache = False
result = None # type: ignore # Incompatible types in assignment (expression has type "None", variable has type "str")
@@ -506,8 +506,8 @@ class ToolUsage:
event_data = self._prepare_event_data(tool, tool_calling)
event_data.update(
{
"started_at": datetime.datetime.fromtimestamp(started_at),
"finished_at": datetime.datetime.fromtimestamp(finished_at),
"started_at": datetime.fromtimestamp(started_at),
"finished_at": datetime.fromtimestamp(finished_at),
"from_cache": from_cache,
}
)

View File

@@ -1,6 +1,6 @@
import inspect
import os
from datetime import UTC, datetime
from datetime import datetime
from functools import wraps
from typing import Any, Awaitable, Callable, Dict, List, Optional
from uuid import uuid4
@@ -14,6 +14,7 @@ from crewai.traces.models import (
LLMResponse,
ToolCall,
)
from crewai.utilities.datetime_compat import UTC
class UnifiedTraceController:

View File

@@ -1,4 +1,5 @@
from .converter import Converter, ConverterError
from .datetime_compat import UTC
from .file_handler import FileHandler
from .i18n import I18N
from .internal_instructor import InternalInstructor
@@ -22,6 +23,7 @@ __all__ = [
"Printer",
"Prompts",
"RPMController",
"UTC",
"YamlParser",
"LLMContextLengthExceededException",
"EmbeddingConfigurator",

View File

@@ -0,0 +1,6 @@
"""Compatibility module for datetime functionality across Python versions."""
from datetime import timezone
# Provide UTC timezone constant that works in Python 3.10+
# This is equivalent to datetime.UTC in Python 3.11+
UTC = timezone.utc

View File

@@ -1,7 +1,7 @@
"""Test Agent creation and execution basic functionality."""
import os
from datetime import UTC, datetime, timezone
from datetime import datetime, timezone
from unittest import mock
from unittest.mock import patch
@@ -18,6 +18,7 @@ from crewai.tools import tool
from crewai.tools.tool_calling import InstructorToolCalling
from crewai.tools.tool_usage import ToolUsage
from crewai.utilities import RPMController
from crewai.utilities.datetime_compat import UTC
from crewai.utilities.events import crewai_event_bus
from crewai.utilities.events.tool_usage_events import ToolUsageFinishedEvent
@@ -916,9 +917,10 @@ def test_tool_result_as_answer_is_the_final_answer_for_the_agent():
@pytest.mark.vcr(filter_headers=["authorization"])
def test_tool_usage_information_is_appended_to_agent():
from datetime import UTC, datetime
from datetime import datetime
from crewai.tools import BaseTool
from crewai.utilities.datetime_compat import UTC
class MyCustomTool(BaseTool):
name: str = "Decide Greetings"
@@ -928,8 +930,9 @@ def test_tool_usage_information_is_appended_to_agent():
return "Howdy!"
fixed_datetime = datetime(2025, 2, 10, 12, 0, 0, tzinfo=UTC)
with patch("datetime.datetime") as mock_datetime:
with patch("crewai.tools.tool_usage.datetime") as mock_datetime:
mock_datetime.now.return_value = fixed_datetime
mock_datetime.fromtimestamp = datetime.fromtimestamp
mock_datetime.side_effect = lambda *args, **kw: datetime(*args, **kw)
agent1 = Agent(

View File

@@ -1,5 +1,5 @@
import os
from datetime import UTC, datetime
from datetime import datetime
from unittest.mock import MagicMock, patch
from uuid import UUID
@@ -21,6 +21,7 @@ from crewai.traces.unified_trace_controller import (
trace_flow_step,
trace_llm_call,
)
from crewai.utilities.datetime_compat import UTC
class TestUnifiedTraceController:

View File

@@ -0,0 +1,14 @@
"""Test datetime compatibility module."""
from datetime import timezone
from crewai.utilities.datetime_compat import UTC
def test_utc_timezone_compatibility():
"""Test that UTC timezone is compatible with both Python 3.10 and 3.11+"""
assert UTC == timezone.utc
assert UTC.tzname(None) == "UTC"
# Verify it works with datetime.now()
from datetime import datetime
dt = datetime.now(UTC)
assert dt.tzinfo == timezone.utc