Skip to content

Commit 2bc3acc

Browse files
committed
fix: keep docling imports lazy
Add a subprocess regression test for import crewai so future changes do not pull docling, docling_core, torch, or transformers into the base import path. Also pin torch and torchvision through the workspace overrides so Python 3.13 resolves torch 2.12 and the matching torchvision line. Torch 2.11.0 fails to import on CPython 3.13.8, while older Python versions keep looser upper bounds and are not forced below the 2.12 line.
1 parent ee70702 commit 2bc3acc

3 files changed

Lines changed: 111 additions & 68 deletions

File tree

lib/crewai/tests/test_imports.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""Test that all public API classes are properly importable."""
22

3+
import os
4+
import subprocess
5+
import sys
6+
37

48
def test_task_output_import():
59
"""Test that TaskOutput can be imported from crewai."""
@@ -13,3 +17,34 @@ def test_crew_output_import():
1317
from crewai import CrewOutput
1418

1519
assert CrewOutput is not None
20+
21+
22+
def test_import_crewai_does_not_import_heavy_optional_deps():
23+
"""`import crewai` must not eagerly import heavy optional dependencies.
24+
25+
``docling`` and its transitive dependencies (``torch``, ``transformers``) are
26+
optional and only needed when ``CrewDoclingSource`` is instantiated. Importing
27+
them at module load made ``import crewai`` slow and could fail outright on
28+
environments where the optional stack does not import cleanly (e.g. ``torch``
29+
on some CPython 3.13 builds). They must be imported lazily; this guards against
30+
a regression. A subprocess is used so the check is unaffected by modules other
31+
tests may have already imported into this process.
32+
"""
33+
code = (
34+
"import sys\n"
35+
"import crewai # noqa: F401\n"
36+
"heavy = [m for m in ('torch', 'docling', 'docling_core', 'transformers') if m in sys.modules]\n"
37+
"print(','.join(sorted(heavy)))\n"
38+
)
39+
result = subprocess.run(
40+
[sys.executable, "-c", code],
41+
capture_output=True,
42+
text=True,
43+
check=True,
44+
env={**os.environ, "CREWAI_DISABLE_TELEMETRY": "true", "OTEL_SDK_DISABLED": "true"},
45+
)
46+
leaked = result.stdout.strip()
47+
assert not leaked, (
48+
f"`import crewai` eagerly imported heavy optional dependencies: {leaked}. "
49+
"Import them lazily (only when actually used)."
50+
)

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ exclude-newer = "3 days"
192192
# starlette <1.0.1 has PYSEC-2026-161 (missing Host header validation poisons request.url.path, bypassing path-based auth). Transitive via fastapi.
193193
# litellm 1.83.8+ hard-pins openai==2.24.0, missing openai.types.responses used by crewai;
194194
# override to >=2.30.0 (the version litellm 1.83.7 used) until upstream relaxes the pin.
195+
# torch 2.11.0 fails to import on CPython 3.13.8; torchvision 0.27.0 is the matching
196+
# release for torch 2.12.0.
195197
override-dependencies = [
196198
"openai>=2.30.0,<3",
197199
"rich>=13.7.1",
@@ -201,6 +203,10 @@ override-dependencies = [
201203
"langchain-text-splitters>=1.1.2,<2",
202204
"urllib3>=2.7.0",
203205
"transformers>=5.4.0; python_version >= '3.10'",
206+
"torch<2.13.0; python_version < '3.13'",
207+
"torch>=2.12.0,<2.13.0; python_version >= '3.13'",
208+
"torchvision<0.28.0; python_version < '3.13'",
209+
"torchvision>=0.27.0,<0.28.0; python_version >= '3.13'",
204210
"cryptography>=46.0.7",
205211
"pypdf>=6.10.2,<7",
206212
"uv>=0.11.15,<1",

0 commit comments

Comments
 (0)