|
| 1 | +import importlib |
| 2 | +import re |
| 3 | +import sys |
1 | 4 | from typing import List, Optional, Any, Iterator |
2 | 5 | from unittest import mock |
3 | 6 | from unittest.mock import Mock |
@@ -382,6 +385,34 @@ def test_span_origin(sentry_init, capture_events): |
382 | 385 | assert span["origin"] == "auto.ai.langchain" |
383 | 386 |
|
384 | 387 |
|
| 388 | +def test_langchain_module_is_optional(monkeypatch): |
| 389 | + """ |
| 390 | + Test that the LangchainIntegration can be imported and set up |
| 391 | + even if the langchain module is not installed. |
| 392 | + """ |
| 393 | + |
| 394 | + lc_re = re.compile(r"^langchain(\..*)?$") |
| 395 | + |
| 396 | + stripped_modules = { |
| 397 | + name: mod for name, mod in sys.modules.items() if not lc_re.match(name) |
| 398 | + } |
| 399 | + |
| 400 | + class HideModuleImportHook(importlib.abc.MetaPathFinder): |
| 401 | + def find_spec(self, fullname, path, target=..., /): |
| 402 | + if lc_re.match(fullname): |
| 403 | + raise ModuleNotFoundError(f"No module named '{fullname}'") |
| 404 | + return None |
| 405 | + |
| 406 | + with ( |
| 407 | + mock.patch.dict(sys.modules, stripped_modules, clear=True), |
| 408 | + mock.patch.object(sys, "meta_path", [HideModuleImportHook(), *sys.meta_path]), |
| 409 | + mock.patch("sentry_sdk.integrations.langchain.manager"), |
| 410 | + ): |
| 411 | + from sentry_sdk.integrations.langchain import LangchainIntegration |
| 412 | + |
| 413 | + LangchainIntegration().setup_once() |
| 414 | + |
| 415 | + |
385 | 416 | def test_manual_callback_no_duplication(sentry_init): |
386 | 417 | """ |
387 | 418 | Test that when a user manually provides a SentryLangchainCallback, |
|
0 commit comments