fix: widen OpenTelemetry version constraints to >=1.34.0,<2 (fixes #4474)

The opentelemetry-api, opentelemetry-sdk, and opentelemetry-exporter-otlp-proto-http
dependencies were pinned to ~=1.34.0 (>=1.34.0,<1.35.0), which conflicts with
google-adk and other libraries requiring >=1.36.0.

Widened to >=1.34.0,<2 to allow compatible newer versions while staying within
the stable 1.x API.

Co-Authored-By: João <joao@crewai.com>
This commit is contained in:
Devin AI
2026-02-13 08:59:52 +00:00
parent f7e3b4dbe0
commit 82a17d208b
3 changed files with 97 additions and 6 deletions

View File

@@ -16,9 +16,9 @@ dependencies = [
"pdfplumber~=0.11.4",
"regex~=2026.1.15",
# Telemetry and Monitoring
"opentelemetry-api~=1.34.0",
"opentelemetry-sdk~=1.34.0",
"opentelemetry-exporter-otlp-proto-http~=1.34.0",
"opentelemetry-api>=1.34.0,<2",
"opentelemetry-sdk>=1.34.0,<2",
"opentelemetry-exporter-otlp-proto-http>=1.34.0,<2",
# Data Handling
"chromadb~=1.1.0",
"tokenizers~=0.20.3",

View File

@@ -0,0 +1,91 @@
import os
import threading
from importlib.metadata import version as pkg_version
from unittest.mock import patch
import pytest
from packaging.version import Version
from crewai.telemetry import Telemetry
@pytest.fixture(autouse=True)
def cleanup_telemetry():
Telemetry._instance = None
if hasattr(Telemetry, "_lock"):
Telemetry._lock = threading.Lock()
yield
Telemetry._instance = None
if hasattr(Telemetry, "_lock"):
Telemetry._lock = threading.Lock()
@pytest.mark.telemetry
class TestOpenTelemetryCompatibility:
def test_opentelemetry_api_version_not_pinned_to_minor(self):
"""Verify opentelemetry-api accepts versions above 1.34.x (issue #4474).
The dependency must use a range like >=1.34.0,<2 instead of ~=1.34.0
so that libraries such as google-adk (which require >=1.36.0) can
coexist in the same environment.
"""
installed = Version(pkg_version("opentelemetry-api"))
assert installed >= Version("1.34.0")
def test_opentelemetry_sdk_version_not_pinned_to_minor(self):
"""Verify opentelemetry-sdk accepts versions above 1.34.x (issue #4474)."""
installed = Version(pkg_version("opentelemetry-sdk"))
assert installed >= Version("1.34.0")
def test_opentelemetry_exporter_version_not_pinned_to_minor(self):
"""Verify opentelemetry-exporter-otlp-proto-http accepts versions above 1.34.x (issue #4474)."""
installed = Version(pkg_version("opentelemetry-exporter-otlp-proto-http"))
assert installed >= Version("1.34.0")
def test_opentelemetry_imports_are_functional(self):
"""Ensure all OpenTelemetry imports used by crewAI work with the installed version."""
from opentelemetry import baggage, trace
from opentelemetry.context import attach, detach
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
OTLPSpanExporter,
)
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExportResult
from opentelemetry.trace import Span, Status, StatusCode
assert trace is not None
assert baggage is not None
assert attach is not None
assert detach is not None
assert OTLPSpanExporter is not None
assert SERVICE_NAME is not None
assert Resource is not None
assert TracerProvider is not None
assert BatchSpanProcessor is not None
assert SpanExportResult is not None
assert Span is not None
assert Status is not None
assert StatusCode is not None
def test_telemetry_initializes_with_current_opentelemetry(self):
"""Verify Telemetry singleton initializes correctly with the installed OpenTelemetry version."""
with patch.dict(os.environ, {}, clear=True):
with patch("crewai.telemetry.telemetry.TracerProvider"):
telemetry = Telemetry()
assert telemetry.ready is True
def test_tracer_provider_setup_with_current_opentelemetry(self):
"""Verify TracerProvider and BatchSpanProcessor work with the installed OpenTelemetry version."""
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
resource = Resource(attributes={SERVICE_NAME: "test-service"})
provider = TracerProvider(resource=resource)
assert provider is not None
tracer = provider.get_tracer("test-tracer")
assert tracer is not None
provider.shutdown()

6
uv.lock generated
View File

@@ -1300,9 +1300,9 @@ requires-dist = [
{ name = "openai", specifier = ">=1.83.0,<3" },
{ name = "openpyxl", specifier = "~=3.1.5" },
{ name = "openpyxl", marker = "extra == 'openpyxl'", specifier = "~=3.1.5" },
{ name = "opentelemetry-api", specifier = "~=1.34.0" },
{ name = "opentelemetry-exporter-otlp-proto-http", specifier = "~=1.34.0" },
{ name = "opentelemetry-sdk", specifier = "~=1.34.0" },
{ name = "opentelemetry-api", specifier = ">=1.34.0,<2" },
{ name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.34.0,<2" },
{ name = "opentelemetry-sdk", specifier = ">=1.34.0,<2" },
{ name = "pandas", marker = "extra == 'pandas'", specifier = "~=2.2.3" },
{ name = "pdfplumber", specifier = "~=0.11.4" },
{ name = "portalocker", specifier = "~=2.7.0" },