lmnr 0.7.3__tar.gz → 0.7.4__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 (95) hide show
  1. {lmnr-0.7.3 → lmnr-0.7.4}/PKG-INFO +1 -1
  2. {lmnr-0.7.3 → lmnr-0.7.4}/pyproject.toml +2 -2
  3. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +2 -2
  4. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/__init__.py +3 -3
  5. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/attributes.py +2 -0
  6. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/processor.py +7 -7
  7. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/laminar.py +52 -2
  8. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/types.py +8 -2
  9. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/version.py +1 -1
  10. {lmnr-0.7.3 → lmnr-0.7.4}/README.md +0 -0
  11. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/__init__.py +0 -0
  12. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/cli.py +0 -0
  13. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/.flake8 +0 -0
  14. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/__init__.py +0 -0
  15. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/decorators/__init__.py +0 -0
  16. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/litellm/__init__.py +0 -0
  17. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/litellm/utils.py +0 -0
  18. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +0 -0
  19. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +0 -0
  20. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +0 -0
  21. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +0 -0
  22. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +0 -0
  23. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +0 -0
  24. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +0 -0
  25. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +0 -0
  26. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +0 -0
  27. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/config.py +0 -0
  28. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +0 -0
  29. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +0 -0
  30. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +0 -0
  31. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +0 -0
  32. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +0 -0
  33. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +0 -0
  34. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +0 -0
  35. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +0 -0
  36. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +0 -0
  37. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +0 -0
  38. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/utils.py +0 -0
  39. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +0 -0
  40. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +0 -0
  41. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +0 -0
  42. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +0 -0
  43. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +0 -0
  44. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +0 -0
  45. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +0 -0
  46. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +0 -0
  47. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +0 -0
  48. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +0 -0
  49. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +0 -0
  50. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +0 -0
  51. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +0 -0
  52. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +0 -0
  53. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +0 -0
  54. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +0 -0
  55. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +0 -0
  56. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +0 -0
  57. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +0 -0
  58. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/context.py +0 -0
  59. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/exporter.py +0 -0
  60. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/instruments.py +0 -0
  61. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/tracing/tracer.py +0 -0
  62. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/utils/__init__.py +0 -0
  63. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/utils/json_encoder.py +0 -0
  64. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/opentelemetry_lib/utils/package_check.py +0 -0
  65. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/py.typed +0 -0
  66. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/__init__.py +0 -0
  67. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/__init__.py +0 -0
  68. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/browser_use_otel.py +0 -0
  69. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/patchright_otel.py +0 -0
  70. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/playwright_otel.py +0 -0
  71. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/pw_utils.py +0 -0
  72. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/recorder/record.umd.min.cjs +0 -0
  73. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/browser/utils.py +0 -0
  74. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/async_client.py +0 -0
  75. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/__init__.py +0 -0
  76. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/agent.py +0 -0
  77. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/base.py +0 -0
  78. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/browser_events.py +0 -0
  79. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/evals.py +0 -0
  80. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/evaluators.py +0 -0
  81. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/asynchronous/resources/tags.py +0 -0
  82. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/__init__.py +0 -0
  83. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/agent.py +0 -0
  84. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/base.py +0 -0
  85. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/browser_events.py +0 -0
  86. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/evals.py +0 -0
  87. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/evaluators.py +0 -0
  88. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/resources/tags.py +0 -0
  89. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/client/synchronous/sync_client.py +0 -0
  90. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/datasets.py +0 -0
  91. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/decorators.py +0 -0
  92. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/eval_control.py +0 -0
  93. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/evaluations.py +0 -0
  94. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/log.py +0 -0
  95. {lmnr-0.7.3 → lmnr-0.7.4}/src/lmnr/sdk/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lmnr
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: Python SDK for Laminar
5
5
  Author: lmnr.ai
6
6
  Author-email: lmnr.ai <founders@lmnr.ai>
@@ -6,7 +6,7 @@
6
6
 
7
7
  [project]
8
8
  name = "lmnr"
9
- version = "0.7.3"
9
+ version = "0.7.4"
10
10
  description = "Python SDK for Laminar"
11
11
  authors = [
12
12
  { name = "lmnr.ai", email = "founders@lmnr.ai" }
@@ -124,7 +124,7 @@ dev = [
124
124
  "pytest-asyncio>=0.26.0",
125
125
  "playwright>=1.52.0",
126
126
  "vcrpy>=7.0.0",
127
- "openai>=1.99.3",
127
+ "openai>=1.99.7",
128
128
  "pytest-recording>=0.13.4",
129
129
  "patchright>=1.52.3",
130
130
  "google-genai>=1.19.0",
@@ -56,8 +56,8 @@ from opentelemetry.trace import SpanKind, Tracer
56
56
  from opentelemetry.trace.status import Status, StatusCode
57
57
  from wrapt import ObjectProxy
58
58
 
59
- from openai.types.chat import ChatCompletionMessageToolCall
60
59
  from openai.types.chat.chat_completion_message import FunctionCall
60
+ import pydantic
61
61
 
62
62
  SPAN_NAME = "openai.chat"
63
63
  PROMPT_FILTER_KEY = "prompt_filter_results"
@@ -995,7 +995,7 @@ async def _abuild_from_streaming_response(
995
995
 
996
996
 
997
997
  def _parse_tool_calls(
998
- tool_calls: Optional[List[Union[dict, ChatCompletionMessageToolCall]]],
998
+ tool_calls: Optional[List[Union[dict, pydantic.BaseModel]]],
999
999
  ) -> Union[List[ToolCall], None]:
1000
1000
  """
1001
1001
  Util to correctly parse the tool calls data from the OpenAI API to this module's
@@ -74,7 +74,7 @@ class TracerWrapper(object):
74
74
  if not hasattr(cls, "instance"):
75
75
  cls._initialize_logger(cls)
76
76
  obj = super(TracerWrapper, cls).__new__(cls)
77
-
77
+
78
78
  # Store session recording options
79
79
  cls.session_recording_options = session_recording_options or {}
80
80
 
@@ -249,13 +249,13 @@ class TracerWrapper(object):
249
249
  self._logger.warning("TracerWrapper not fully initialized, cannot flush")
250
250
  return False
251
251
  return self._span_processor.force_flush()
252
-
252
+
253
253
  @classmethod
254
254
  def get_session_recording_options(cls) -> SessionRecordingOptions:
255
255
  """Get the session recording options set during initialization."""
256
256
  return cls.session_recording_options
257
257
 
258
- def get_tracer(self):
258
+ def get_tracer(self) -> trace.Tracer:
259
259
  if self._tracer_provider is None:
260
260
  return trace.get_tracer_provider().get_tracer(TRACER_NAME)
261
261
  return self._tracer_provider.get_tracer(TRACER_NAME)
@@ -14,6 +14,8 @@ SPAN_OUTPUT = "lmnr.span.output"
14
14
  SPAN_TYPE = "lmnr.span.type"
15
15
  SPAN_PATH = "lmnr.span.path"
16
16
  SPAN_IDS_PATH = "lmnr.span.ids_path"
17
+ PARENT_SPAN_PATH = "lmnr.span.parent_path"
18
+ PARENT_SPAN_IDS_PATH = "lmnr.span.parent_ids_path"
17
19
  SPAN_INSTRUMENTATION_SOURCE = "lmnr.span.instrumentation_source"
18
20
  SPAN_SDK_VERSION = "lmnr.span.sdk_version"
19
21
  SPAN_LANGUAGE_VERSION = "lmnr.span.language_version"
@@ -7,9 +7,11 @@ from opentelemetry.sdk.trace.export import (
7
7
  SimpleSpanProcessor,
8
8
  )
9
9
  from opentelemetry.sdk.trace import Span
10
- from opentelemetry.context import Context, get_value, get_current, set_value
10
+ from opentelemetry.context import Context, get_value
11
11
 
12
12
  from lmnr.opentelemetry_lib.tracing.attributes import (
13
+ PARENT_SPAN_IDS_PATH,
14
+ PARENT_SPAN_PATH,
13
15
  SPAN_IDS_PATH,
14
16
  SPAN_INSTRUMENTATION_SOURCE,
15
17
  SPAN_LANGUAGE_VERSION,
@@ -52,20 +54,18 @@ class LaminarSpanProcessor(SpanProcessor):
52
54
  )
53
55
 
54
56
  def on_start(self, span: Span, parent_context: Context | None = None):
55
- span_path_in_context = get_value("span_path", parent_context or get_current())
56
- parent_span_path = span_path_in_context or (
57
+ parent_span_path = list(span.attributes.get(PARENT_SPAN_PATH, tuple())) or (
57
58
  self.__span_id_to_path.get(span.parent.span_id) if span.parent else None
58
59
  )
59
- parent_span_ids_path = (
60
- self.__span_id_lists.get(span.parent.span_id, []) if span.parent else []
61
- )
60
+ parent_span_ids_path = list(
61
+ span.attributes.get(PARENT_SPAN_IDS_PATH, tuple())
62
+ ) or (self.__span_id_lists.get(span.parent.span_id, []) if span.parent else [])
62
63
  span_path = parent_span_path + [span.name] if parent_span_path else [span.name]
63
64
  span_ids_path = parent_span_ids_path + [
64
65
  str(uuid.UUID(int=span.get_span_context().span_id))
65
66
  ]
66
67
  span.set_attribute(SPAN_PATH, span_path)
67
68
  span.set_attribute(SPAN_IDS_PATH, span_ids_path)
68
- set_value("span_path", span_path, get_current())
69
69
  self.__span_id_to_path[span.get_span_context().span_id] = span_path
70
70
  self.__span_id_lists[span.get_span_context().span_id] = span_ids_path
71
71
 
@@ -13,6 +13,10 @@ from lmnr.opentelemetry_lib.tracing.instruments import Instruments
13
13
  from lmnr.opentelemetry_lib.tracing.tracer import get_tracer_with_context
14
14
  from lmnr.opentelemetry_lib.tracing.attributes import (
15
15
  ASSOCIATION_PROPERTIES,
16
+ PARENT_SPAN_IDS_PATH,
17
+ PARENT_SPAN_PATH,
18
+ SPAN_IDS_PATH,
19
+ SPAN_PATH,
16
20
  USER_ID,
17
21
  Attributes,
18
22
  SPAN_TYPE,
@@ -316,9 +320,29 @@ class Laminar:
316
320
 
317
321
  with get_tracer_with_context() as (tracer, isolated_context):
318
322
  ctx = context or isolated_context
323
+ path = []
324
+ span_ids_path = []
319
325
  if parent_span_context is not None:
326
+ if isinstance(parent_span_context, (dict, str)):
327
+ try:
328
+ laminar_span_context = LaminarSpanContext.deserialize(
329
+ parent_span_context
330
+ )
331
+ path = laminar_span_context.span_path
332
+ span_ids_path = laminar_span_context.span_ids_path
333
+ except Exception:
334
+ cls.__logger.warning(
335
+ f"`start_as_current_span` Could not deserialize parent_span_context: {parent_span_context}. "
336
+ "Will use it as is."
337
+ )
338
+ laminar_span_context = parent_span_context
339
+ else:
340
+ laminar_span_context = parent_span_context
341
+ if isinstance(laminar_span_context, LaminarSpanContext):
342
+ path = laminar_span_context.span_path
343
+ span_ids_path = laminar_span_context.span_ids_path
320
344
  span_context = LaminarSpanContext.try_to_otel_span_context(
321
- parent_span_context, cls.__logger
345
+ laminar_span_context, cls.__logger
322
346
  )
323
347
  ctx = trace.set_span_in_context(
324
348
  trace.NonRecordingSpan(span_context), ctx
@@ -352,6 +376,8 @@ class Laminar:
352
376
  context=ctx,
353
377
  attributes={
354
378
  SPAN_TYPE: span_type,
379
+ PARENT_SPAN_PATH: path,
380
+ PARENT_SPAN_IDS_PATH: span_ids_path,
355
381
  **(label_props),
356
382
  **(tag_props),
357
383
  },
@@ -454,9 +480,29 @@ class Laminar:
454
480
 
455
481
  with get_tracer_with_context() as (tracer, isolated_context):
456
482
  ctx = context or isolated_context
483
+ path = []
484
+ span_ids_path = []
457
485
  if parent_span_context is not None:
486
+ if isinstance(parent_span_context, (dict, str)):
487
+ try:
488
+ laminar_span_context = LaminarSpanContext.deserialize(
489
+ parent_span_context
490
+ )
491
+ path = laminar_span_context.span_path
492
+ span_ids_path = laminar_span_context.span_ids_path
493
+ except Exception:
494
+ cls.__logger.warning(
495
+ f"`start_span` Could not deserialize parent_span_context: {parent_span_context}. "
496
+ "Will use it as is."
497
+ )
498
+ laminar_span_context = parent_span_context
499
+ else:
500
+ laminar_span_context = parent_span_context
501
+ if isinstance(laminar_span_context, LaminarSpanContext):
502
+ path = laminar_span_context.span_path
503
+ span_ids_path = laminar_span_context.span_ids_path
458
504
  span_context = LaminarSpanContext.try_to_otel_span_context(
459
- parent_span_context, cls.__logger
505
+ laminar_span_context, cls.__logger
460
506
  )
461
507
  ctx = trace.set_span_in_context(
462
508
  trace.NonRecordingSpan(span_context), ctx
@@ -491,6 +537,8 @@ class Laminar:
491
537
  context=ctx,
492
538
  attributes={
493
539
  SPAN_TYPE: span_type,
540
+ PARENT_SPAN_PATH: path,
541
+ PARENT_SPAN_IDS_PATH: span_ids_path,
494
542
  **(label_props),
495
543
  **(tag_props),
496
544
  },
@@ -662,6 +710,8 @@ class Laminar:
662
710
  trace_id=uuid.UUID(int=span.get_span_context().trace_id),
663
711
  span_id=uuid.UUID(int=span.get_span_context().span_id),
664
712
  is_remote=span.get_span_context().is_remote,
713
+ span_path=span.attributes.get(SPAN_PATH, []),
714
+ span_ids_path=span.attributes.get(SPAN_IDS_PATH, []),
665
715
  )
666
716
 
667
717
  @classmethod
@@ -169,6 +169,8 @@ class LaminarSpanContext(pydantic.BaseModel):
169
169
  trace_id: uuid.UUID
170
170
  span_id: uuid.UUID
171
171
  is_remote: bool = pydantic.Field(default=False)
172
+ span_path: list[str] = pydantic.Field(default=[])
173
+ span_ids_path: list[str] = pydantic.Field(default=[]) # stringified UUIDs
172
174
 
173
175
  def __str__(self) -> str:
174
176
  return self.model_dump_json()
@@ -199,7 +201,7 @@ class LaminarSpanContext(pydantic.BaseModel):
199
201
  "Please use `LaminarSpanContext` instead."
200
202
  )
201
203
  return span_context
202
- elif isinstance(span_context, dict) or isinstance(span_context, str):
204
+ elif isinstance(span_context, (dict, str)):
203
205
  try:
204
206
  laminar_span_context = cls.deserialize(span_context)
205
207
  return SpanContext(
@@ -221,6 +223,9 @@ class LaminarSpanContext(pydantic.BaseModel):
221
223
  "trace_id": data.get("trace_id") or data.get("traceId"),
222
224
  "span_id": data.get("span_id") or data.get("spanId"),
223
225
  "is_remote": data.get("is_remote") or data.get("isRemote", False),
226
+ "span_path": data.get("span_path") or data.get("spanPath", []),
227
+ "span_ids_path": data.get("span_ids_path")
228
+ or data.get("spanIdsPath", []),
224
229
  }
225
230
  return cls.model_validate(converted_data)
226
231
  elif isinstance(data, str):
@@ -356,5 +361,6 @@ class MaskInputOptions(TypedDict):
356
361
  email: bool | None
357
362
  tel: bool | None
358
363
 
364
+
359
365
  class SessionRecordingOptions(TypedDict):
360
- mask_input_options: MaskInputOptions | None
366
+ mask_input_options: MaskInputOptions | None
@@ -3,7 +3,7 @@ import httpx
3
3
  from packaging import version
4
4
 
5
5
 
6
- __version__ = "0.7.3"
6
+ __version__ = "0.7.4"
7
7
  PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}"
8
8
 
9
9
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes