langtrace-python-sdk 1.2.12__tar.gz → 1.2.16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/PKG-INFO +1 -1
  2. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/extensions/langtrace_exporter.py +0 -2
  3. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/anthropic/instrumentation.py +4 -0
  4. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/chroma/instrumentation.py +3 -0
  5. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain/instrumentation.py +4 -0
  6. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/llamaindex/instrumentation.py +4 -0
  7. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/openai/instrumentation.py +7 -4
  8. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/openai/patch.py +4 -6
  9. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/pinecone/instrumentation.py +4 -0
  10. langtrace_python_sdk-1.2.16/src/langtrace_python_sdk/version.py +1 -0
  11. langtrace_python_sdk-1.2.16/src/tests/anthropic/test_anthropic.py +72 -0
  12. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/tests/chroma/test_chroma.py +5 -0
  13. langtrace_python_sdk-1.2.16/src/tests/langchain/test_langchain.py +68 -0
  14. langtrace_python_sdk-1.2.16/src/tests/langchain/test_langchain_community.py +68 -0
  15. langtrace_python_sdk-1.2.16/src/tests/langchain/test_langchain_core.py +113 -0
  16. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/tests/openai/test_chat_completion.py +25 -30
  17. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/tests/openai/test_image_generation.py +7 -4
  18. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/tests/pinecone/test_pinecone.py +6 -0
  19. langtrace_python_sdk-1.2.16/src/tests/utils.py +21 -0
  20. langtrace_python_sdk-1.2.12/src/langtrace_python_sdk/version.py +0 -1
  21. langtrace_python_sdk-1.2.12/src/tests/utils.py +0 -17
  22. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/.gitignore +0 -0
  23. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/LICENSE +0 -0
  24. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/README.md +0 -0
  25. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/pyproject.toml +0 -0
  26. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/__init__.py +0 -0
  27. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/__init__.py +0 -0
  28. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/anthropic_example/__init__.py +0 -0
  29. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/anthropic_example/completion.py +0 -0
  30. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/chroma_example/__init__.py +0 -0
  31. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/chroma_example/basic.py +0 -0
  32. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/langchain_example/__init__.py +0 -0
  33. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/langchain_example/basic.py +0 -0
  34. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/langchain_example/tool.py +0 -0
  35. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/llamaindex_example/__init__.py +0 -0
  36. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/llamaindex_example/basic.py +0 -0
  37. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/llamaindex_example/data/abramov.txt +0 -0
  38. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/openai/__init__.py +0 -0
  39. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/openai/chat_completion.py +0 -0
  40. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/openai/embeddings_create.py +0 -0
  41. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/openai/function_calling.py +0 -0
  42. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/openai/images_generate.py +0 -0
  43. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/pinecone_example/__init__.py +0 -0
  44. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/examples/pinecone_example/basic.py +0 -0
  45. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/__init__.py +0 -0
  46. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/__init__.py +0 -0
  47. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/exporter/langtrace_exporter.py +0 -0
  48. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/instrumentation/__init__.py +0 -0
  49. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/instrumentation/anthropic.py +0 -0
  50. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/instrumentation/chroma.py +0 -0
  51. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/instrumentation/common.py +0 -0
  52. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/instrumentation/openai.py +0 -0
  53. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/constants/instrumentation/pinecone.py +0 -0
  54. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/extensions/__init__.py +0 -0
  55. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/__init__.py +0 -0
  56. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/anthropic/__init__.py +0 -0
  57. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/anthropic/patch.py +0 -0
  58. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/chroma/__init__.py +0 -0
  59. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/chroma/patch.py +0 -0
  60. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain/__init__.py +0 -0
  61. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain/patch.py +0 -0
  62. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain_community/__init__.py +0 -0
  63. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain_community/instrumentation.py +0 -0
  64. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain_community/patch.py +0 -0
  65. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain_core/__init__.py +0 -0
  66. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain_core/instrumentation.py +0 -0
  67. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/langchain_core/patch.py +0 -0
  68. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/llamaindex/__init__.py +0 -0
  69. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/llamaindex/patch.py +0 -0
  70. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/openai/__init__.py +0 -0
  71. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/pinecone/__init__.py +0 -0
  72. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/instrumentation/pinecone/patch.py +0 -0
  73. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/langtrace.py +0 -0
  74. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/utils/__init__.py +0 -0
  75. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/utils/llm.py +0 -0
  76. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/langtrace_python_sdk/utils/with_root_span.py +0 -0
  77. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/run_example.py +0 -0
  78. {langtrace_python_sdk-1.2.12 → langtrace_python_sdk-1.2.16}/src/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langtrace-python-sdk
3
- Version: 1.2.12
3
+ Version: 1.2.16
4
4
  Summary: Python SDK for LangTrace
5
5
  Project-URL: Homepage, https://github.com/Scale3-Labs/langtrace-python-sdk
6
6
  Author-email: Scale3 Labs <engineering@scale3labs.com>
@@ -90,10 +90,8 @@ class LangTraceExporter(SpanExporter):
90
90
  data=json.dumps(data),
91
91
  headers={"Content-Type": "application/json", "x-api-key": self.api_key},
92
92
  )
93
- print(f"Traces sent To {LANGTRACE_REMOTE_URL}")
94
93
  return SpanExportResult.SUCCESS
95
94
  except Exception as e:
96
- print("Error sending data to remote URL", e)
97
95
  return SpanExportResult.FAILURE
98
96
 
99
97
  def shutdown(self) -> None:
@@ -11,6 +11,10 @@ from wrapt import wrap_function_wrapper
11
11
 
12
12
  from langtrace_python_sdk.instrumentation.anthropic.patch import messages_create
13
13
 
14
+ import logging
15
+
16
+ logging.basicConfig(level=logging.FATAL)
17
+
14
18
 
15
19
  class AnthropicInstrumentation(BaseInstrumentor):
16
20
  """
@@ -11,6 +11,9 @@ from wrapt import wrap_function_wrapper
11
11
 
12
12
  from langtrace_python_sdk.constants.instrumentation.chroma import APIS
13
13
  from langtrace_python_sdk.instrumentation.chroma.patch import collection_patch
14
+ import logging
15
+
16
+ logging.basicConfig(level=logging.FATAL)
14
17
 
15
18
 
16
19
  class ChromaInstrumentation(BaseInstrumentor):
@@ -12,6 +12,10 @@ from wrapt import wrap_function_wrapper
12
12
 
13
13
  from langtrace_python_sdk.instrumentation.langchain.patch import generic_patch
14
14
 
15
+ import logging
16
+
17
+ logging.basicConfig(level=logging.FATAL)
18
+
15
19
 
16
20
  def patch_module_classes(
17
21
  module_name, tracer, version, task, trace_output=True, trace_input=True
@@ -12,6 +12,10 @@ from wrapt import wrap_function_wrapper
12
12
 
13
13
  from langtrace_python_sdk.instrumentation.llamaindex.patch import generic_patch
14
14
 
15
+ import logging
16
+
17
+ logging.basicConfig(level=logging.FATAL)
18
+
15
19
 
16
20
  class LlamaindexInstrumentation(BaseInstrumentor):
17
21
  """
@@ -1,7 +1,6 @@
1
1
  import importlib.metadata
2
2
  from typing import Collection
3
3
 
4
- import openai
5
4
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
6
5
  from opentelemetry.trace import get_tracer
7
6
  from wrapt import wrap_function_wrapper
@@ -12,6 +11,10 @@ from langtrace_python_sdk.instrumentation.openai.patch import (
12
11
  images_generate,
13
12
  )
14
13
 
14
+ import logging
15
+
16
+ logging.basicConfig(level=logging.FATAL)
17
+
15
18
 
16
19
  class OpenAIInstrumentation(BaseInstrumentor):
17
20
 
@@ -25,17 +28,17 @@ class OpenAIInstrumentation(BaseInstrumentor):
25
28
  wrap_function_wrapper(
26
29
  "openai.resources.chat.completions",
27
30
  "Completions.create",
28
- chat_completions_create(openai.chat.completions.create, version, tracer),
31
+ chat_completions_create("openai.chat.completions.create", version, tracer),
29
32
  )
30
33
  wrap_function_wrapper(
31
34
  "openai.resources.images",
32
35
  "Images.generate",
33
- images_generate(openai.images.generate, version, tracer),
36
+ images_generate("openai.images.generate", version, tracer),
34
37
  )
35
38
  wrap_function_wrapper(
36
39
  "openai.resources.embeddings",
37
40
  "Embeddings.create",
38
- embeddings_create(openai.embeddings.create, version, tracer),
41
+ embeddings_create("openai.embeddings.create", version, tracer),
39
42
  )
40
43
 
41
44
  def _uninstrument(self, **kwargs):
@@ -52,7 +52,7 @@ def images_generate(original_method, version, tracer):
52
52
  span.set_attribute(field, value)
53
53
  try:
54
54
  # Attempt to call the original method
55
- result = original_method(*args, **kwargs)
55
+ result = wrapped(*args, **kwargs)
56
56
  if kwargs.get("stream") is False or kwargs.get("stream") is None:
57
57
  data = (
58
58
  result.data[0]
@@ -132,8 +132,8 @@ def chat_completions_create(original_method, version, tracer):
132
132
  span.set_attribute(field, value)
133
133
  try:
134
134
  # Attempt to call the original method
135
- result = original_method(*args, **kwargs)
136
- if kwargs.get("stream") is False:
135
+ result = wrapped(*args, **kwargs)
136
+ if kwargs.get("stream") is False or kwargs.get("stream") is None:
137
137
  span.set_attribute("llm.model", result.model)
138
138
  if hasattr(result, "choices") and result.choices is not None:
139
139
  responses = [
@@ -338,14 +338,12 @@ def embeddings_create(original_method, version, tracer):
338
338
  APIS["EMBEDDINGS_CREATE"]["METHOD"], kind=SpanKind.CLIENT
339
339
  ) as span:
340
340
 
341
- print("Inside embeddings_create", trace.get_current_span())
342
-
343
341
  for field, value in attributes.model_dump(by_alias=True).items():
344
342
  if value is not None:
345
343
  span.set_attribute(field, value)
346
344
  try:
347
345
  # Attempt to call the original method
348
- result = original_method(*args, **kwargs)
346
+ result = wrapped(*args, **kwargs)
349
347
  span.set_status(StatusCode.OK)
350
348
  return result
351
349
  except Exception as e:
@@ -14,6 +14,10 @@ from wrapt import wrap_function_wrapper
14
14
  from langtrace_python_sdk.constants.instrumentation.pinecone import APIS
15
15
  from langtrace_python_sdk.instrumentation.pinecone.patch import generic_patch
16
16
 
17
+ import logging
18
+
19
+ logging.basicConfig(level=logging.FATAL)
20
+
17
21
 
18
22
  class PineconeInstrumentation(BaseInstrumentor):
19
23
  """
@@ -0,0 +1 @@
1
+ __version__ = "1.2.16"
@@ -0,0 +1,72 @@
1
+ import unittest
2
+ from unittest.mock import MagicMock, call
3
+ from langtrace_python_sdk.instrumentation.anthropic.patch import messages_create
4
+ from opentelemetry.trace import SpanKind
5
+ import importlib.metadata
6
+ from langtrace_python_sdk.constants.instrumentation.anthropic import APIS
7
+ from opentelemetry.trace.status import Status, StatusCode
8
+ import json
9
+ from langtrace.trace_attributes import Event, LLMSpanAttributes
10
+
11
+ from tests.utils import common_setup
12
+
13
+ class TestAnthropic(unittest.TestCase):
14
+
15
+ data = {
16
+ "content" : [MagicMock(text="Some text", type="text")],
17
+ "system_fingerprint" : "None",
18
+ "usage" : MagicMock(input_tokens=23, output_tokens=44),
19
+ "chunks" : [MagicMock(delta="Some text", message="text")]}
20
+
21
+
22
+ def setUp(self):
23
+
24
+ # Mock the original method
25
+ self.anthropic_mock, self.tracer, self.span = common_setup(self.data, None)
26
+
27
+ def tearDown(self):
28
+ pass
29
+
30
+ def test_anthropic(self):
31
+ # Arrange
32
+ version = importlib.metadata.version('anthropic')
33
+ kwargs = {
34
+ "model": "claude-3-opus-20240229",
35
+ "messages" : [{"role": "user", "content": "How are you today?"}],
36
+ "stream": False
37
+ }
38
+
39
+ # Act
40
+ wrapped_function = messages_create("anthropic.messages.create", version, self.tracer)
41
+ result = wrapped_function(self.anthropic_mock, MagicMock(), (), kwargs)
42
+
43
+
44
+ # Assert
45
+ self.assertTrue(self.tracer.start_as_current_span.called_once_with("anthropic.messages.create", kind=SpanKind.CLIENT))
46
+ self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
47
+
48
+ expected_attributes = {
49
+ "langtrace.service.name": "Anthropic",
50
+ "langtrace.service.type": "llm",
51
+ "langtrace.service.version": version,
52
+ "langtrace.version": "1.0.0",
53
+ "url.full": "/v1/messages",
54
+ "llm.api": APIS["MESSAGES_CREATE"]["ENDPOINT"],
55
+ "llm.model": kwargs.get("model"),
56
+ "llm.prompts": json.dumps(kwargs.get("messages", [])),
57
+ "llm.stream": kwargs.get("stream"),
58
+ }
59
+
60
+ self.assertTrue(
61
+ self.span.set_attribute.has_calls(
62
+ [call(key, value) for key, value in expected_attributes.items()], any_order=True
63
+ )
64
+ )
65
+
66
+ expected_result_data = {"system_fingerprint": "None" }
67
+
68
+ self.assertEqual(result.system_fingerprint, expected_result_data["system_fingerprint"])
69
+
70
+
71
+ if __name__ == '__main__':
72
+ unittest.main()
@@ -49,6 +49,11 @@ class TestChromaPatch(unittest.TestCase):
49
49
  }
50
50
  for key, value in expected_attributes.items():
51
51
  self.span.set_attribute.assert_has_calls([call(key, value)], any_order=True)
52
+
53
+ actual_calls = self.span.set_attribute.call_args_list
54
+
55
+ for key, value in expected_attributes.items():
56
+ self.assertIn(call(key, value), actual_calls)
52
57
 
53
58
  # Assert the span status is set to OK
54
59
  self.span.set_status.assert_called_with(StatusCode.OK)
@@ -0,0 +1,68 @@
1
+
2
+ import unittest
3
+ from unittest.mock import MagicMock, call
4
+ from langtrace_python_sdk.instrumentation.langchain.patch import generic_patch
5
+ from opentelemetry.trace import SpanKind
6
+ from opentelemetry.trace import get_tracer
7
+ import importlib.metadata
8
+ from langtrace_python_sdk.constants.instrumentation.openai import APIS
9
+ from opentelemetry.trace.status import Status, StatusCode
10
+ from tests.utils import common_setup
11
+ import json
12
+
13
+ class TestGenericPatch(unittest.TestCase):
14
+ data = {"key": "value"}
15
+ def setUp(self):
16
+ self.langchain_mock, self.tracer, self.span = common_setup(self.data, None)
17
+
18
+ def tearDown(self):
19
+ # Clean up after each test case
20
+ pass
21
+
22
+ def test_generic_patch(self):
23
+ # Arrange
24
+ method_name = "example_method"
25
+ trace_output = False
26
+ trace_input = False # Change as per your requirement
27
+ args = (1, 2, 3)
28
+ task = "split_text"
29
+ kwargs = {'key': 'value'}
30
+ version = importlib.metadata.version('langchain')
31
+
32
+ # Act
33
+ wrapped_function = generic_patch("langchain.text_splitter", task, self.tracer, version, trace_output, trace_input)
34
+ result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
35
+
36
+ # Assert
37
+ self.assertTrue(self.tracer.start_as_current_span.called_once_with(method_name, kind=SpanKind.CLIENT))
38
+
39
+ service_provider = "Langchain"
40
+ expected_attributes = {
41
+ "langtrace.service.name": service_provider,
42
+ "langtrace.service.type": "framework",
43
+ "langtrace.service.version": version,
44
+ "langtrace.version": "1.0.0",
45
+ "langchain.task.name": task,
46
+ }
47
+
48
+
49
+ self.assertTrue(
50
+ self.span.set_attribute.has_calls(
51
+ [call(key, value) for key, value in expected_attributes.items()], any_order=True
52
+ )
53
+ )
54
+
55
+ actual_calls = self.span.set_attribute.call_args_list
56
+
57
+ for key, value in expected_attributes.items():
58
+ self.assertIn(call(key, value), actual_calls)
59
+
60
+ self.assertEqual(self.span.set_status.call_count, 1)
61
+ self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
62
+
63
+ expected_result_data = {"key": "value" }
64
+
65
+ self.assertEqual(result.key, expected_result_data["key"])
66
+
67
+ if __name__ == '__main__':
68
+ unittest.main()
@@ -0,0 +1,68 @@
1
+
2
+ import unittest
3
+ from unittest.mock import MagicMock, Mock, patch, call
4
+ from langtrace_python_sdk.instrumentation.langchain_community.patch import generic_patch
5
+ from opentelemetry.trace import SpanKind
6
+ from opentelemetry.trace import get_tracer
7
+ import importlib.metadata
8
+ import openai
9
+ from langtrace_python_sdk.constants.instrumentation.openai import APIS
10
+ from opentelemetry.trace.status import Status, StatusCode
11
+ import json
12
+ from tests.utils import common_setup
13
+ class TestGenericPatch(unittest.TestCase):
14
+ data = {"key": "value"}
15
+ def setUp(self):
16
+ self.langchain_mock, self.tracer, self.span = common_setup(self.data, None)
17
+
18
+ def tearDown(self):
19
+ # Clean up after each test case
20
+ pass
21
+
22
+ def test_generic_patch(self):
23
+ # Arrange
24
+ method_name = "example_method"
25
+ trace_output = False
26
+ trace_input = False
27
+ args = (1, 2, 3)
28
+ task = "vector_store"
29
+ kwargs = {'key': 'value'}
30
+ version = importlib.metadata.version("langchain-community")
31
+
32
+ # Act
33
+ wrapped_function = generic_patch("langchain_community.vectorstores.faiss", task, self.tracer, version, trace_output, trace_input)
34
+ result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
35
+
36
+ # Assert
37
+ self.assertTrue(self.tracer.start_as_current_span.called_once_with(method_name, kind=SpanKind.CLIENT))
38
+
39
+ service_provider = "Langchain Community"
40
+ expected_attributes = {
41
+ "langtrace.service.name": service_provider,
42
+ "langtrace.service.type": "framework",
43
+ "langtrace.service.version": version,
44
+ "langtrace.version": "1.0.0",
45
+ "langchain.task.name": task,
46
+ }
47
+
48
+
49
+ self.assertTrue(
50
+ self.span.set_attribute.has_calls(
51
+ [call(key, value) for key, value in expected_attributes.items()], any_order=True
52
+ )
53
+ )
54
+
55
+ actual_calls = self.span.set_attribute.call_args_list
56
+
57
+ for key, value in expected_attributes.items():
58
+ self.assertIn(call(key, value), actual_calls)
59
+
60
+ self.assertEqual(self.span.set_status.call_count, 1)
61
+ self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
62
+
63
+ expected_result_data = {"key": "value" }
64
+ self.assertEqual(result.key, expected_result_data["key"])
65
+
66
+
67
+ if __name__ == '__main__':
68
+ unittest.main()
@@ -0,0 +1,113 @@
1
+
2
+ import unittest
3
+ from unittest.mock import MagicMock, Mock, patch, call
4
+ from langtrace_python_sdk.instrumentation.langchain_core.patch import generic_patch, runnable_patch
5
+ from opentelemetry.trace import SpanKind
6
+ from opentelemetry.trace import get_tracer
7
+ import importlib.metadata
8
+ import openai
9
+ from langtrace_python_sdk.constants.instrumentation.openai import APIS
10
+ from opentelemetry.trace.status import Status, StatusCode
11
+ import json
12
+ from tests.utils import common_setup
13
+ class TestGenericPatch(unittest.TestCase):
14
+ data = {"items": "value"}
15
+ def setUp(self):
16
+ self.langchain_mock, self.tracer, self.span = common_setup(self.data, None)
17
+
18
+ def tearDown(self):
19
+ # Clean up after each test case
20
+ pass
21
+
22
+ def test_generic_patch(self):
23
+ # Arrange
24
+ method_name = "example_method"
25
+ trace_output = False
26
+ trace_input = True
27
+ task = "retriever"
28
+ args = (1, 2, 3)
29
+ kwargs = {'key': 'value'}
30
+ version = importlib.metadata.version("langchain-core")
31
+
32
+ # Act
33
+ wrapped_function = generic_patch("langchain_core.retrievers", task , self.tracer, version, trace_output, trace_input)
34
+ result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
35
+
36
+ # Assert
37
+ self.assertTrue(self.tracer.start_as_current_span.called_once_with(method_name, kind=SpanKind.CLIENT))
38
+
39
+ service_provider = "Langchain Core"
40
+ expected_attributes = {
41
+ "langtrace.service.name": service_provider,
42
+ "langtrace.service.type": "framework",
43
+ "langtrace.service.version": version,
44
+ "langtrace.version": "1.0.0",
45
+ "langchain.task.name": task,
46
+ }
47
+
48
+ self.assertTrue(
49
+ self.span.set_attribute.has_calls(
50
+ [call(key, value) for key, value in expected_attributes.items()], any_order=True
51
+ )
52
+ )
53
+
54
+ actual_calls = self.span.set_attribute.call_args_list
55
+ for key, value in expected_attributes.items():
56
+ self.assertIn(call(key, value), actual_calls)
57
+
58
+
59
+ self.assertEqual(self.span.set_status.call_count, 1)
60
+ self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
61
+
62
+ expected_result_data = {"items": "value" }
63
+ self.assertEqual(result.items, expected_result_data["items"])
64
+
65
+ def test_runnable_patch(self):
66
+ # Arrange
67
+ method_name = "example_method"
68
+ trace_output = False
69
+ trace_input = True
70
+ args = (1, 2, 3)
71
+ kwargs = {'key': 'value'}
72
+ version = importlib.metadata.version("langchain-core")
73
+
74
+ # Act
75
+ wrapped_function = runnable_patch("langchain_core.runnables.passthrough",
76
+ "runnablepassthrough", self.tracer, version, trace_output, trace_input)
77
+
78
+ result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
79
+
80
+ # Assert
81
+ self.assertTrue(self.tracer.start_as_current_span.called_once_with(method_name, kind=SpanKind.CLIENT))
82
+
83
+ service_provider = "Langchain Core"
84
+ expected_attributes = {
85
+ "langtrace.service.name": service_provider,
86
+ "langtrace.service.type": "framework",
87
+ "langtrace.service.version": version,
88
+ "langtrace.version": "1.0.0",
89
+ "langchain.task.name": "runnablepassthrough",
90
+ }
91
+
92
+ self.assertTrue(
93
+ self.span.set_attribute.has_calls(
94
+ [call(key, value) for key, value in expected_attributes.items()], any_order=True
95
+ )
96
+ )
97
+
98
+ actual_calls = self.span.set_attribute.call_args_list
99
+
100
+ for key, value in expected_attributes.items():
101
+ self.assertIn(call(key, value), actual_calls)
102
+
103
+
104
+ self.assertEqual(self.span.set_status.call_count, 1)
105
+ self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
106
+
107
+ expected_result_data = {"items": "value" }
108
+
109
+ self.assertEqual(result.items, expected_result_data["items"])
110
+
111
+
112
+ if __name__ == '__main__':
113
+ unittest.main()
@@ -10,38 +10,35 @@ from opentelemetry.trace.status import Status, StatusCode
10
10
  import json
11
11
  from tests.utils import common_setup
12
12
  class TestChatCompletion(unittest.TestCase):
13
+
13
14
  data = {
14
15
  "id": "chatcmpl-93wIW4A2r0YjlDvx7PKvHV0VxbprP",
15
- "choices": [
16
- {
17
- "finish_reason": "stop",
18
- "index": 0,
19
- "logprobs": None,
20
- "message": {
21
- "content": "This is a test, this is a test, this is a test.",
22
- "role": "assistant",
23
- "function_call": None,
24
- "tool_calls": None
25
- }
26
- }
16
+ "choices":[
17
+ MagicMock(
18
+ finish_reason="stop",
19
+ index=0,
20
+ logprobs=None,
21
+ message=MagicMock(
22
+ content="This is a test, this is a test, this is a test.",
23
+ role="assistant",
24
+ function_call=None,
25
+ tool_calls=None
26
+ )
27
+ )
27
28
  ],
28
29
  "created": 1710726108,
29
30
  "model": "gpt-4-0613",
30
31
  "object": "chat.completion",
31
32
  "system_fingerprint": None,
32
- "usage": {
33
- "completion_tokens": 15,
34
- "prompt_tokens": 14,
35
- "total_tokens": 29
36
- }
33
+ "usage": MagicMock(prompt_tokens = 14, completion_tokens = 15, total_tokens = 29)
37
34
  }
38
35
 
39
36
  def setUp(self):
40
- self.openai_mock, self.tracer, self.span = common_setup(self.data, 'openai.chat.completions.create')
41
-
42
-
37
+ self.openai_mock, self.tracer, self.span = common_setup(self.data, None)
38
+
39
+
43
40
  def tearDown(self):
44
- self.openai_mock.stop()
41
+ pass
45
42
 
46
43
  def test_chat_completions_create_non_streaming(self):
47
44
  # Arrange
@@ -49,15 +46,18 @@ class TestChatCompletion(unittest.TestCase):
49
46
  llm_model_value = 'gpt-4'
50
47
  messages_value = [{'role': 'user', 'content': 'Say this is a test three times'}]
51
48
 
49
+
52
50
  kwargs = {
53
51
  'model': llm_model_value,
54
52
  'messages': messages_value,
55
53
  'stream': False,
56
54
  }
57
55
 
56
+
58
57
  # Act
59
- wrapped_function = chat_completions_create(openai.chat.completions.create, version, self.tracer)
58
+ wrapped_function = chat_completions_create(self.openai_mock, version, self.tracer)
60
59
  result = wrapped_function(MagicMock(), MagicMock(), (), kwargs)
60
+
61
61
 
62
62
  # Assert
63
63
  self.assertTrue(self.tracer.start_as_current_span.called_once_with("openai.chat.completions.create", kind=SpanKind.CLIENT))
@@ -79,17 +79,12 @@ class TestChatCompletion(unittest.TestCase):
79
79
  )
80
80
  )
81
81
 
82
- self.assertEqual(self.span.set_status.call_count, 1)
83
82
  self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
84
83
 
85
- expected_result = ['id', 'choices', 'created', 'model', 'system_fingerprint', 'object', 'usage']
86
- result_keys = json.loads(result).keys()
87
- self.assertSetEqual(set(expected_result), set(result_keys), "Keys mismatch")
84
+ expected_result_data = {"model": "gpt-4-0613"}
85
+
86
+ self.assertEqual(result.model, expected_result_data["model"])
88
87
 
89
- expected_content = "This is a test, this is a test, this is a test."
90
- self.assertEqual(
91
- json.loads(result).get('choices')[0].get('message').get('content'), expected_content, "Content mismatch"
92
- )
93
88
 
94
89
  if __name__ == '__main__':
95
90
  unittest.main()
@@ -3,6 +3,7 @@ from unittest.mock import MagicMock, Mock, patch, call
3
3
  from langtrace_python_sdk.instrumentation.openai.patch import images_generate
4
4
  from opentelemetry.trace import SpanKind
5
5
  from opentelemetry.trace import get_tracer
6
+ from opentelemetry import baggage
6
7
  import importlib.metadata
7
8
  import openai
8
9
  from langtrace_python_sdk.constants.instrumentation.openai import APIS
@@ -11,6 +12,7 @@ from opentelemetry.trace.status import Status, StatusCode
11
12
  import json
12
13
  from tests.utils import common_setup
13
14
 
15
+
14
16
  class TestImageGeneration(unittest.TestCase):
15
17
  data = {
16
18
  "created": 1710983755,
@@ -24,7 +26,7 @@ class TestImageGeneration(unittest.TestCase):
24
26
  }
25
27
 
26
28
  def setUp(self):
27
- self.openai_mock, self.tracer, self.span = common_setup(self.data, 'openai.images.generate')
29
+ self.openai_mock, self.tracer, self.span = common_setup(self.data, "openai.images.generate")
28
30
 
29
31
 
30
32
  def tearDown(self):
@@ -38,7 +40,8 @@ class TestImageGeneration(unittest.TestCase):
38
40
  kwargs = {
39
41
  'model': llm_model_value,
40
42
  'prompt': prompt_value,
41
- 'stream': False }
43
+ 'stream': False }
44
+
42
45
 
43
46
  # Act
44
47
  wrapped_function = images_generate(openai.images.generate, version, self.tracer)
@@ -48,7 +51,7 @@ class TestImageGeneration(unittest.TestCase):
48
51
  self.assertTrue(self.tracer.start_as_current_span.called_once_with("openai.images.generate", kind=SpanKind.CLIENT))
49
52
 
50
53
  expected_attributes = {
51
- "langtrace.service.name": 'OpenAI',
54
+ "langtrace.service.name": "OpenAI",
52
55
  "langtrace.service.type": "llm",
53
56
  "langtrace.service.version": version,
54
57
  "langtrace.version": "1.0.0",
@@ -56,7 +59,7 @@ class TestImageGeneration(unittest.TestCase):
56
59
  "llm.api": "images_generation_endpoint",
57
60
  "llm.model": kwargs.get('model'),
58
61
  "llm.stream": kwargs.get('stream'),
59
- "llm.prompts": json.dumps([kwargs.get('prompt', [])])
62
+ "llm.prompts": json.dumps([kwargs.get('prompt', [])]),
60
63
  }
61
64
  self.assertTrue(self.span.set_attribute.has_calls([call(key, value) for key, value in expected_attributes.items()], any_order=True))
62
65
  self.assertTrue(self.span.set_status.called_once_with(Status(StatusCode.OK)))
@@ -54,6 +54,12 @@ class TestPinecone(unittest.TestCase):
54
54
  [call(key, value) for key, value in expected_attributes.items()], any_order=True
55
55
  )
56
56
  )
57
+
58
+ actual_calls = self.span.set_attribute.call_args_list
59
+
60
+ for key, value in expected_attributes.items():
61
+ self.assertIn(call(key, value), actual_calls)
62
+
57
63
  self.assertEqual(self.span.set_status.call_count, 1)
58
64
  self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
59
65
 
@@ -0,0 +1,21 @@
1
+ from unittest.mock import MagicMock, patch
2
+ import json
3
+
4
+ def common_setup(data, method_to_mock=None):
5
+ if method_to_mock:
6
+ service_mock = patch(method_to_mock)
7
+ mock_method = service_mock.start()
8
+ mock_method.return_value = json.dumps(data)
9
+ else:
10
+ service_mock = MagicMock()
11
+ service_mock.return_value = MagicMock(**data)
12
+
13
+
14
+ tracer = MagicMock()
15
+ span = MagicMock()
16
+
17
+ context_manager_mock = MagicMock()
18
+ context_manager_mock.__enter__.return_value = span
19
+ tracer.start_as_current_span.return_value = context_manager_mock
20
+
21
+ return service_mock, tracer, span
@@ -1 +0,0 @@
1
- __version__ = "1.2.12"
@@ -1,17 +0,0 @@
1
- import importlib.metadata
2
- from unittest.mock import MagicMock, patch
3
- import json
4
-
5
- def common_setup(data, method_to_mock):
6
- service_mock = patch(method_to_mock)
7
- mock_image_generate = service_mock.start()
8
- mock_image_generate.return_value = json.dumps(data)
9
-
10
- tracer = MagicMock()
11
- span = MagicMock()
12
-
13
- context_manager_mock = MagicMock()
14
- context_manager_mock.__enter__.return_value = span
15
- tracer.start_as_current_span.return_value = context_manager_mock
16
-
17
- return service_mock, tracer, span