mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-11 17:18:29 +00:00
fix: loosen dependency constraints to fix OPIK integration conflict
This commit addresses issue #4201 where crewAI's overly restrictive dependency constraints (using ~= operator) caused conflicts when installing alongside packages like opik. Changes: - Changed dependency constraints from ~= (compatible release) to >= (minimum version) for core dependencies in crewai and crewai-tools - Key dependencies loosened: openai, pydantic, pydantic-settings, opentelemetry-*, and others - Added tests to verify dependency constraints remain flexible The ~= operator was too restrictive as it only allows patch version updates (e.g., openai~=1.83.0 means >=1.83.0,<1.84.0). This caused dependency resolution failures when other packages needed different versions of shared dependencies. Fixes #4201 Co-Authored-By: João <joao@crewai.com>
This commit is contained in:
@@ -8,17 +8,16 @@ authors = [
|
|||||||
]
|
]
|
||||||
requires-python = ">=3.10, <3.14"
|
requires-python = ">=3.10, <3.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lancedb~=0.5.4",
|
"lancedb>=0.5.4",
|
||||||
"pytube~=15.0.0",
|
"pytube>=15.0.0",
|
||||||
"requests~=2.32.5",
|
"requests>=2.32.5",
|
||||||
"docker~=7.1.0",
|
"docker>=7.1.0",
|
||||||
"crewai==1.8.0",
|
"crewai>=1.8.0",
|
||||||
"lancedb~=0.5.4",
|
"tiktoken>=0.8.0",
|
||||||
"tiktoken~=0.8.0",
|
"beautifulsoup4>=4.12.3",
|
||||||
"beautifulsoup4~=4.13.4",
|
"python-docx>=1.1.0",
|
||||||
"python-docx~=1.2.0",
|
"youtube-transcript-api>=0.6.3",
|
||||||
"youtube-transcript-api~=1.2.2",
|
"pymupdf>=1.25.0",
|
||||||
"pymupdf~=1.26.6",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,36 +9,36 @@ authors = [
|
|||||||
requires-python = ">=3.10, <3.14"
|
requires-python = ">=3.10, <3.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
# Core Dependencies
|
# Core Dependencies
|
||||||
"pydantic~=2.11.9",
|
"pydantic>=2.11.9,<3.0.0",
|
||||||
"openai~=1.83.0",
|
"openai>=1.13.3",
|
||||||
"instructor>=1.3.3",
|
"instructor>=1.3.3",
|
||||||
# Text Processing
|
# Text Processing
|
||||||
"pdfplumber~=0.11.4",
|
"pdfplumber>=0.11.4",
|
||||||
"regex~=2024.9.11",
|
"regex>=2024.9.11",
|
||||||
# Telemetry and Monitoring
|
# Telemetry and Monitoring
|
||||||
"opentelemetry-api~=1.34.0",
|
"opentelemetry-api>=1.30.0",
|
||||||
"opentelemetry-sdk~=1.34.0",
|
"opentelemetry-sdk>=1.30.0",
|
||||||
"opentelemetry-exporter-otlp-proto-http~=1.34.0",
|
"opentelemetry-exporter-otlp-proto-http>=1.30.0",
|
||||||
# Data Handling
|
# Data Handling
|
||||||
"chromadb~=1.1.0",
|
"chromadb>=1.0.0",
|
||||||
"tokenizers~=0.20.3",
|
"tokenizers>=0.20.3",
|
||||||
"openpyxl~=3.1.5",
|
"openpyxl>=3.1.5",
|
||||||
# Authentication and Security
|
# Authentication and Security
|
||||||
"python-dotenv~=1.1.1",
|
"python-dotenv>=1.0.0",
|
||||||
"pyjwt~=2.9.0",
|
"pyjwt>=2.9.0",
|
||||||
# Configuration and Utils
|
# Configuration and Utils
|
||||||
"click~=8.1.7",
|
"click>=8.1.7",
|
||||||
"appdirs~=1.4.4",
|
"appdirs>=1.4.4",
|
||||||
"jsonref~=1.1.0",
|
"jsonref>=1.1.0",
|
||||||
"json-repair~=0.25.2",
|
"json-repair>=0.25.2",
|
||||||
"tomli-w~=1.1.0",
|
"tomli-w>=1.1.0",
|
||||||
"tomli~=2.0.2",
|
"tomli>=2.0.2",
|
||||||
"json5~=0.10.0",
|
"json5>=0.10.0",
|
||||||
"portalocker~=2.7.0",
|
"portalocker>=2.7.0",
|
||||||
"pydantic-settings~=2.10.1",
|
"pydantic-settings>=2.10.1,<3.0.0",
|
||||||
"mcp~=1.16.0",
|
"mcp>=1.16.0",
|
||||||
"uv~=0.9.13",
|
"uv>=0.4.25",
|
||||||
"aiosqlite~=0.21.0",
|
"aiosqlite>=0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -49,54 +49,54 @@ Repository = "https://github.com/crewAIInc/crewAI"
|
|||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
tools = [
|
tools = [
|
||||||
"crewai-tools==1.8.0",
|
"crewai-tools>=1.8.0",
|
||||||
]
|
]
|
||||||
embeddings = [
|
embeddings = [
|
||||||
"tiktoken~=0.8.0"
|
"tiktoken>=0.8.0"
|
||||||
]
|
]
|
||||||
pandas = [
|
pandas = [
|
||||||
"pandas~=2.2.3",
|
"pandas>=2.2.3",
|
||||||
]
|
]
|
||||||
openpyxl = [
|
openpyxl = [
|
||||||
"openpyxl~=3.1.5",
|
"openpyxl>=3.1.5",
|
||||||
]
|
]
|
||||||
mem0 = ["mem0ai~=0.1.94"]
|
mem0 = ["mem0ai>=0.1.94"]
|
||||||
docling = [
|
docling = [
|
||||||
"docling~=2.63.0",
|
"docling>=2.12.0",
|
||||||
]
|
]
|
||||||
qdrant = [
|
qdrant = [
|
||||||
"qdrant-client[fastembed]~=1.14.3",
|
"qdrant-client[fastembed]>=1.14.3",
|
||||||
]
|
]
|
||||||
aws = [
|
aws = [
|
||||||
"boto3~=1.40.38",
|
"boto3>=1.40.38",
|
||||||
"aiobotocore~=2.25.2",
|
"aiobotocore>=2.25.2",
|
||||||
]
|
]
|
||||||
watson = [
|
watson = [
|
||||||
"ibm-watsonx-ai~=1.3.39",
|
"ibm-watsonx-ai>=1.3.39",
|
||||||
]
|
]
|
||||||
voyageai = [
|
voyageai = [
|
||||||
"voyageai~=0.3.5",
|
"voyageai>=0.3.5",
|
||||||
]
|
]
|
||||||
litellm = [
|
litellm = [
|
||||||
"litellm~=1.74.9",
|
"litellm>=1.74.9",
|
||||||
]
|
]
|
||||||
bedrock = [
|
bedrock = [
|
||||||
"boto3~=1.40.45",
|
"boto3>=1.40.45",
|
||||||
]
|
]
|
||||||
google-genai = [
|
google-genai = [
|
||||||
"google-genai~=1.49.0",
|
"google-genai>=1.2.0",
|
||||||
]
|
]
|
||||||
azure-ai-inference = [
|
azure-ai-inference = [
|
||||||
"azure-ai-inference~=1.0.0b9",
|
"azure-ai-inference>=1.0.0b9",
|
||||||
]
|
]
|
||||||
anthropic = [
|
anthropic = [
|
||||||
"anthropic~=0.71.0",
|
"anthropic>=0.69.0",
|
||||||
]
|
]
|
||||||
a2a = [
|
a2a = [
|
||||||
"a2a-sdk~=0.3.10",
|
"a2a-sdk>=0.3.10",
|
||||||
"httpx-auth~=0.23.1",
|
"httpx-auth>=0.23.1",
|
||||||
"httpx-sse~=0.4.0",
|
"httpx-sse>=0.4.0",
|
||||||
"aiocache[redis,memcached]~=0.12.3",
|
"aiocache[redis,memcached]>=0.12.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
171
lib/crewai/tests/test_dependency_compatibility.py
Normal file
171
lib/crewai/tests/test_dependency_compatibility.py
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
"""Test that crewai dependencies are compatible with common integrations.
|
||||||
|
|
||||||
|
This test module verifies that crewai's dependency constraints are flexible enough
|
||||||
|
to allow installation alongside common third-party packages like opik for monitoring.
|
||||||
|
|
||||||
|
Related issue: https://github.com/crewAIInc/crewAI/issues/4201
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import tomli
|
||||||
|
|
||||||
|
|
||||||
|
def get_pyproject_path() -> Path:
|
||||||
|
"""Get the path to the crewai pyproject.toml file."""
|
||||||
|
return Path(__file__).parent.parent / "pyproject.toml"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_pyproject() -> dict:
|
||||||
|
"""Parse the pyproject.toml file."""
|
||||||
|
pyproject_path = get_pyproject_path()
|
||||||
|
with open(pyproject_path, "rb") as f:
|
||||||
|
return tomli.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def test_openai_dependency_is_flexible():
|
||||||
|
"""Test that openai dependency uses >= instead of ~= to allow version flexibility.
|
||||||
|
|
||||||
|
The ~= operator (compatible release) is too restrictive and can cause dependency
|
||||||
|
conflicts with packages like opik that also depend on openai.
|
||||||
|
|
||||||
|
For example, openai~=1.83.0 means >=1.83.0,<1.84.0 which is very restrictive.
|
||||||
|
Using openai>=1.13.3 allows any version >= 1.13.3 which is more flexible.
|
||||||
|
"""
|
||||||
|
pyproject = parse_pyproject()
|
||||||
|
dependencies = pyproject["project"]["dependencies"]
|
||||||
|
|
||||||
|
openai_dep = None
|
||||||
|
for dep in dependencies:
|
||||||
|
if dep.startswith("openai"):
|
||||||
|
openai_dep = dep
|
||||||
|
break
|
||||||
|
|
||||||
|
assert openai_dep is not None, "openai dependency not found in pyproject.toml"
|
||||||
|
|
||||||
|
# Check that it uses >= instead of ~=
|
||||||
|
assert "~=" not in openai_dep, (
|
||||||
|
f"openai dependency should use >= instead of ~= for flexibility. "
|
||||||
|
f"Found: {openai_dep}"
|
||||||
|
)
|
||||||
|
assert ">=" in openai_dep, (
|
||||||
|
f"openai dependency should use >= for minimum version. Found: {openai_dep}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pydantic_dependency_allows_minor_updates():
|
||||||
|
"""Test that pydantic dependency allows minor version updates within v2.
|
||||||
|
|
||||||
|
Using pydantic>=2.x.x,<3.0.0 allows minor updates while staying within v2.
|
||||||
|
"""
|
||||||
|
pyproject = parse_pyproject()
|
||||||
|
dependencies = pyproject["project"]["dependencies"]
|
||||||
|
|
||||||
|
pydantic_dep = None
|
||||||
|
for dep in dependencies:
|
||||||
|
if dep.startswith("pydantic") and not dep.startswith("pydantic-settings"):
|
||||||
|
pydantic_dep = dep
|
||||||
|
break
|
||||||
|
|
||||||
|
assert pydantic_dep is not None, "pydantic dependency not found in pyproject.toml"
|
||||||
|
|
||||||
|
# Check that it uses >= and <3.0.0 instead of ~=
|
||||||
|
assert "~=" not in pydantic_dep, (
|
||||||
|
f"pydantic dependency should use >= instead of ~= for flexibility. "
|
||||||
|
f"Found: {pydantic_dep}"
|
||||||
|
)
|
||||||
|
assert ">=" in pydantic_dep, (
|
||||||
|
f"pydantic dependency should use >= for minimum version. Found: {pydantic_dep}"
|
||||||
|
)
|
||||||
|
assert "<3.0.0" in pydantic_dep, (
|
||||||
|
f"pydantic dependency should have <3.0.0 upper bound. Found: {pydantic_dep}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pydantic_settings_dependency_allows_minor_updates():
|
||||||
|
"""Test that pydantic-settings dependency allows minor version updates within v2."""
|
||||||
|
pyproject = parse_pyproject()
|
||||||
|
dependencies = pyproject["project"]["dependencies"]
|
||||||
|
|
||||||
|
pydantic_settings_dep = None
|
||||||
|
for dep in dependencies:
|
||||||
|
if dep.startswith("pydantic-settings"):
|
||||||
|
pydantic_settings_dep = dep
|
||||||
|
break
|
||||||
|
|
||||||
|
assert (
|
||||||
|
pydantic_settings_dep is not None
|
||||||
|
), "pydantic-settings dependency not found in pyproject.toml"
|
||||||
|
|
||||||
|
# Check that it uses >= and <3.0.0 instead of ~=
|
||||||
|
assert "~=" not in pydantic_settings_dep, (
|
||||||
|
f"pydantic-settings dependency should use >= instead of ~= for flexibility. "
|
||||||
|
f"Found: {pydantic_settings_dep}"
|
||||||
|
)
|
||||||
|
assert ">=" in pydantic_settings_dep, (
|
||||||
|
f"pydantic-settings dependency should use >= for minimum version. "
|
||||||
|
f"Found: {pydantic_settings_dep}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_core_dependencies_use_flexible_constraints():
|
||||||
|
"""Test that core dependencies use >= instead of ~= for flexibility.
|
||||||
|
|
||||||
|
The ~= operator is too restrictive for most dependencies and can cause
|
||||||
|
conflicts with third-party packages.
|
||||||
|
"""
|
||||||
|
pyproject = parse_pyproject()
|
||||||
|
dependencies = pyproject["project"]["dependencies"]
|
||||||
|
|
||||||
|
# These are core dependencies that should use flexible constraints
|
||||||
|
core_deps = [
|
||||||
|
"openai",
|
||||||
|
"pydantic",
|
||||||
|
"opentelemetry-api",
|
||||||
|
"opentelemetry-sdk",
|
||||||
|
"click",
|
||||||
|
]
|
||||||
|
|
||||||
|
for core_dep in core_deps:
|
||||||
|
matching_dep = None
|
||||||
|
for dep in dependencies:
|
||||||
|
if dep.startswith(core_dep):
|
||||||
|
matching_dep = dep
|
||||||
|
break
|
||||||
|
|
||||||
|
if matching_dep:
|
||||||
|
assert "~=" not in matching_dep, (
|
||||||
|
f"{core_dep} dependency should use >= instead of ~= for flexibility. "
|
||||||
|
f"Found: {matching_dep}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_overly_restrictive_pinning():
|
||||||
|
"""Test that dependencies don't use overly restrictive pinning.
|
||||||
|
|
||||||
|
Dependencies should not use == (exact version) or ~= (compatible release)
|
||||||
|
unless there's a specific reason documented.
|
||||||
|
"""
|
||||||
|
pyproject = parse_pyproject()
|
||||||
|
dependencies = pyproject["project"]["dependencies"]
|
||||||
|
|
||||||
|
for dep in dependencies:
|
||||||
|
# Skip comments
|
||||||
|
if dep.strip().startswith("#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check for exact version pinning (==)
|
||||||
|
# Allow == only if there's a known reason
|
||||||
|
if "==" in dep:
|
||||||
|
# Currently no dependencies should use ==
|
||||||
|
assert False, (
|
||||||
|
f"Dependency uses exact version pinning (==) which is too restrictive: {dep}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check for compatible release (~=)
|
||||||
|
if "~=" in dep:
|
||||||
|
assert False, (
|
||||||
|
f"Dependency uses compatible release (~=) which can be too restrictive: {dep}. "
|
||||||
|
f"Consider using >= instead."
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user