lmnr 0.6.16__py3-none-any.whl → 0.7.26__py3-none-any.whl

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 (113) hide show
  1. lmnr/__init__.py +6 -15
  2. lmnr/cli/__init__.py +270 -0
  3. lmnr/cli/datasets.py +371 -0
  4. lmnr/{cli.py → cli/evals.py} +20 -102
  5. lmnr/cli/rules.py +42 -0
  6. lmnr/opentelemetry_lib/__init__.py +9 -2
  7. lmnr/opentelemetry_lib/decorators/__init__.py +274 -168
  8. lmnr/opentelemetry_lib/litellm/__init__.py +352 -38
  9. lmnr/opentelemetry_lib/litellm/utils.py +82 -0
  10. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +849 -0
  11. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +13 -0
  12. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +211 -0
  13. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +41 -0
  14. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +401 -0
  15. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +425 -0
  16. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +332 -0
  17. lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +1 -0
  18. lmnr/opentelemetry_lib/opentelemetry/instrumentation/claude_agent/__init__.py +451 -0
  19. lmnr/opentelemetry_lib/opentelemetry/instrumentation/claude_agent/proxy.py +144 -0
  20. lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_agent/__init__.py +100 -0
  21. lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/__init__.py +476 -0
  22. lmnr/opentelemetry_lib/opentelemetry/instrumentation/cua_computer/utils.py +12 -0
  23. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +191 -129
  24. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +26 -0
  25. lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +126 -41
  26. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +488 -0
  27. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +8 -0
  28. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +143 -0
  29. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +41 -0
  30. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +229 -0
  31. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +92 -0
  32. lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +1 -0
  33. lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/__init__.py +381 -0
  34. lmnr/opentelemetry_lib/opentelemetry/instrumentation/kernel/utils.py +36 -0
  35. lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +16 -16
  36. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +61 -0
  37. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +472 -0
  38. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +1185 -0
  39. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +305 -0
  40. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +16 -0
  41. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +312 -0
  42. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +100 -0
  43. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +41 -0
  44. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +68 -0
  45. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +197 -0
  46. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +176 -0
  47. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +368 -0
  48. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +325 -0
  49. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +135 -0
  50. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +786 -0
  51. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +1 -0
  52. lmnr/opentelemetry_lib/opentelemetry/instrumentation/openhands_ai/__init__.py +388 -0
  53. lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +69 -0
  54. lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +59 -61
  55. lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +197 -0
  56. lmnr/opentelemetry_lib/tracing/__init__.py +119 -18
  57. lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +124 -25
  58. lmnr/opentelemetry_lib/tracing/attributes.py +4 -0
  59. lmnr/opentelemetry_lib/tracing/context.py +200 -0
  60. lmnr/opentelemetry_lib/tracing/exporter.py +109 -15
  61. lmnr/opentelemetry_lib/tracing/instruments.py +22 -5
  62. lmnr/opentelemetry_lib/tracing/processor.py +128 -30
  63. lmnr/opentelemetry_lib/tracing/span.py +398 -0
  64. lmnr/opentelemetry_lib/tracing/tracer.py +40 -1
  65. lmnr/opentelemetry_lib/tracing/utils.py +62 -0
  66. lmnr/opentelemetry_lib/utils/package_check.py +9 -0
  67. lmnr/opentelemetry_lib/utils/wrappers.py +11 -0
  68. lmnr/sdk/browser/background_send_events.py +158 -0
  69. lmnr/sdk/browser/browser_use_cdp_otel.py +100 -0
  70. lmnr/sdk/browser/browser_use_otel.py +12 -12
  71. lmnr/sdk/browser/bubus_otel.py +71 -0
  72. lmnr/sdk/browser/cdp_utils.py +518 -0
  73. lmnr/sdk/browser/inject_script.js +514 -0
  74. lmnr/sdk/browser/patchright_otel.py +18 -44
  75. lmnr/sdk/browser/playwright_otel.py +104 -187
  76. lmnr/sdk/browser/pw_utils.py +249 -210
  77. lmnr/sdk/browser/recorder/record.umd.min.cjs +84 -0
  78. lmnr/sdk/browser/utils.py +1 -1
  79. lmnr/sdk/client/asynchronous/async_client.py +47 -15
  80. lmnr/sdk/client/asynchronous/resources/__init__.py +2 -7
  81. lmnr/sdk/client/asynchronous/resources/browser_events.py +1 -0
  82. lmnr/sdk/client/asynchronous/resources/datasets.py +131 -0
  83. lmnr/sdk/client/asynchronous/resources/evals.py +122 -18
  84. lmnr/sdk/client/asynchronous/resources/evaluators.py +85 -0
  85. lmnr/sdk/client/asynchronous/resources/tags.py +4 -10
  86. lmnr/sdk/client/synchronous/resources/__init__.py +2 -2
  87. lmnr/sdk/client/synchronous/resources/datasets.py +131 -0
  88. lmnr/sdk/client/synchronous/resources/evals.py +83 -17
  89. lmnr/sdk/client/synchronous/resources/evaluators.py +85 -0
  90. lmnr/sdk/client/synchronous/resources/tags.py +4 -10
  91. lmnr/sdk/client/synchronous/sync_client.py +47 -15
  92. lmnr/sdk/datasets/__init__.py +94 -0
  93. lmnr/sdk/datasets/file_utils.py +91 -0
  94. lmnr/sdk/decorators.py +103 -23
  95. lmnr/sdk/evaluations.py +122 -33
  96. lmnr/sdk/laminar.py +816 -333
  97. lmnr/sdk/log.py +7 -2
  98. lmnr/sdk/types.py +124 -143
  99. lmnr/sdk/utils.py +115 -2
  100. lmnr/version.py +1 -1
  101. {lmnr-0.6.16.dist-info → lmnr-0.7.26.dist-info}/METADATA +71 -78
  102. lmnr-0.7.26.dist-info/RECORD +116 -0
  103. lmnr-0.7.26.dist-info/WHEEL +4 -0
  104. lmnr-0.7.26.dist-info/entry_points.txt +3 -0
  105. lmnr/opentelemetry_lib/tracing/context_properties.py +0 -65
  106. lmnr/sdk/browser/rrweb/rrweb.umd.min.cjs +0 -98
  107. lmnr/sdk/client/asynchronous/resources/agent.py +0 -329
  108. lmnr/sdk/client/synchronous/resources/agent.py +0 -323
  109. lmnr/sdk/datasets.py +0 -60
  110. lmnr-0.6.16.dist-info/LICENSE +0 -75
  111. lmnr-0.6.16.dist-info/RECORD +0 -61
  112. lmnr-0.6.16.dist-info/WHEEL +0 -4
  113. lmnr-0.6.16.dist-info/entry_points.txt +0 -3
@@ -2,10 +2,14 @@ import logging
2
2
  import uuid
3
3
 
4
4
  from lmnr.opentelemetry_lib.utils.package_check import is_package_installed
5
- from lmnr.sdk.browser.pw_utils import handle_navigation_async, handle_navigation_sync
5
+ from lmnr.sdk.browser.pw_utils import (
6
+ start_recording_events_async,
7
+ start_recording_events_sync,
8
+ take_full_snapshot,
9
+ take_full_snapshot_async,
10
+ )
6
11
  from lmnr.sdk.browser.utils import with_tracer_and_client_wrapper
7
12
  from lmnr.sdk.client.asynchronous.async_client import AsyncLaminarClient
8
- from lmnr.sdk.client.synchronous.sync_client import LaminarClient
9
13
  from lmnr.version import __version__
10
14
 
11
15
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
@@ -13,29 +17,22 @@ from opentelemetry.instrumentation.utils import unwrap
13
17
  from opentelemetry.trace import (
14
18
  get_tracer,
15
19
  Tracer,
16
- get_current_span,
17
- Span,
18
- INVALID_SPAN,
19
- set_span_in_context,
20
20
  )
21
- from opentelemetry.context import get_current
22
21
  from typing import Collection
23
22
  from wrapt import wrap_function_wrapper
24
23
 
25
24
  try:
26
25
  if is_package_installed("playwright"):
27
- from playwright.async_api import Browser, BrowserContext, Page
26
+ from playwright.async_api import Browser, BrowserContext
28
27
  from playwright.sync_api import (
29
28
  Browser as SyncBrowser,
30
29
  BrowserContext as SyncBrowserContext,
31
- Page as SyncPage,
32
30
  )
33
31
  elif is_package_installed("patchright"):
34
- from patchright.async_api import Browser, BrowserContext, Page
32
+ from patchright.async_api import Browser, BrowserContext
35
33
  from patchright.sync_api import (
36
34
  Browser as SyncBrowser,
37
35
  BrowserContext as SyncBrowserContext,
38
- Page as SyncPage,
39
36
  )
40
37
  else:
41
38
  raise ImportError(
@@ -54,67 +51,26 @@ except ImportError as e:
54
51
  _instruments = ("playwright >= 1.9.0",)
55
52
  logger = logging.getLogger(__name__)
56
53
 
57
- _context_spans: dict[str, Span] = {}
58
-
59
-
60
- @with_tracer_and_client_wrapper
61
- def _wrap_new_page(
62
- tracer: Tracer, client: LaminarClient, to_wrap, wrapped, instance, args, kwargs
63
- ):
64
- with tracer.start_as_current_span(
65
- f"{to_wrap.get('object')}.{to_wrap.get('method')}"
66
- ) as span:
67
- page = wrapped(*args, **kwargs)
68
- session_id = str(uuid.uuid4().hex)
69
- trace_id = format(get_current_span().get_span_context().trace_id, "032x")
70
- span.set_attribute("lmnr.internal.has_browser_session", True)
71
- handle_navigation_sync(page, session_id, trace_id, client)
72
- return page
73
-
74
-
75
- @with_tracer_and_client_wrapper
76
- async def _wrap_new_page_async(
77
- tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
78
- ):
79
- with tracer.start_as_current_span(
80
- f"{to_wrap.get('object')}.{to_wrap.get('method')}"
81
- ) as span:
82
- page = await wrapped(*args, **kwargs)
83
- session_id = str(uuid.uuid4().hex)
84
- trace_id = format(span.get_span_context().trace_id, "032x")
85
- span.set_attribute("lmnr.internal.has_browser_session", True)
86
- await handle_navigation_async(page, session_id, trace_id, client)
87
- return page
88
-
89
54
 
90
55
  @with_tracer_and_client_wrapper
91
56
  def _wrap_new_browser_sync(
92
- tracer: Tracer, client: LaminarClient, to_wrap, wrapped, instance, args, kwargs
57
+ tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
93
58
  ):
94
- global _context_spans
95
59
  browser: SyncBrowser = wrapped(*args, **kwargs)
96
60
  session_id = str(uuid.uuid4().hex)
97
- for context in browser.contexts:
98
- span = get_current_span()
99
- if span == INVALID_SPAN:
100
- span = tracer.start_span(
101
- name=f"{to_wrap.get('object')}.{to_wrap.get('method')}"
102
- )
103
- set_span_in_context(span, get_current())
104
- _context_spans[id(context)] = span
105
- span.set_attribute("lmnr.internal.has_browser_session", True)
106
- trace_id = format(span.get_span_context().trace_id, "032x")
107
-
108
- def handle_page_navigation(page: SyncPage):
109
- return handle_navigation_sync(page, session_id, trace_id, client)
110
-
111
- context.on(
112
- "page",
113
- handle_page_navigation,
114
- )
115
61
 
62
+ def create_page_handler(session_id, client):
63
+ def page_handler(page):
64
+ start_recording_events_sync(page, session_id, client)
65
+
66
+ return page_handler
67
+
68
+ for context in browser.contexts:
69
+ page_handler = create_page_handler(session_id, client)
70
+ context.on("page", page_handler)
116
71
  for page in context.pages:
117
- handle_navigation_sync(page, session_id, trace_id, client)
72
+ start_recording_events_sync(page, session_id, client)
73
+
118
74
  return browser
119
75
 
120
76
 
@@ -122,54 +78,41 @@ def _wrap_new_browser_sync(
122
78
  async def _wrap_new_browser_async(
123
79
  tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
124
80
  ):
125
- global _context_spans
126
81
  browser: Browser = await wrapped(*args, **kwargs)
127
82
  session_id = str(uuid.uuid4().hex)
83
+
84
+ def create_page_handler(session_id, client):
85
+ async def page_handler(page):
86
+ await start_recording_events_async(page, session_id, client)
87
+
88
+ return page_handler
89
+
128
90
  for context in browser.contexts:
129
- span = get_current_span()
130
- if span == INVALID_SPAN:
131
- span = tracer.start_span(
132
- name=f"{to_wrap.get('object')}.{to_wrap.get('method')}"
133
- )
134
- set_span_in_context(span, get_current())
135
- _context_spans[id(context)] = span
136
- span.set_attribute("lmnr.internal.has_browser_session", True)
137
- trace_id = format(span.get_span_context().trace_id, "032x")
138
-
139
- async def handle_page_navigation(page: Page):
140
- return await handle_navigation_async(page, session_id, trace_id, client)
141
-
142
- context.on("page", handle_page_navigation)
91
+ page_handler = create_page_handler(session_id, client)
92
+ context.on("page", page_handler)
143
93
  for page in context.pages:
144
- await handle_navigation_async(page, session_id, trace_id, client)
94
+ await start_recording_events_async(page, session_id, client)
145
95
  return browser
146
96
 
147
97
 
148
98
  @with_tracer_and_client_wrapper
149
99
  def _wrap_new_context_sync(
150
- tracer: Tracer, client: LaminarClient, to_wrap, wrapped, instance, args, kwargs
100
+ tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
151
101
  ):
152
102
  context: SyncBrowserContext = wrapped(*args, **kwargs)
153
103
  session_id = str(uuid.uuid4().hex)
154
- span = get_current_span()
155
- if span == INVALID_SPAN:
156
- span = tracer.start_span(
157
- name=f"{to_wrap.get('object')}.{to_wrap.get('method')}"
158
- )
159
- set_span_in_context(span, get_current())
160
- _context_spans[id(context)] = span
161
- span.set_attribute("lmnr.internal.has_browser_session", True)
162
- trace_id = format(span.get_span_context().trace_id, "032x")
163
-
164
- def handle_page_navigation(page: SyncPage):
165
- return handle_navigation_sync(page, session_id, trace_id, client)
166
-
167
- context.on(
168
- "page",
169
- handle_page_navigation,
170
- )
104
+
105
+ def create_page_handler(session_id, client):
106
+ def page_handler(page):
107
+ start_recording_events_sync(page, session_id, client)
108
+
109
+ return page_handler
110
+
111
+ page_handler = create_page_handler(session_id, client)
112
+ context.on("page", page_handler)
171
113
  for page in context.pages:
172
- handle_navigation_sync(page, session_id, trace_id, client)
114
+ start_recording_events_sync(page, session_id, client)
115
+
173
116
  return context
174
117
 
175
118
 
@@ -179,80 +122,58 @@ async def _wrap_new_context_async(
179
122
  ):
180
123
  context: BrowserContext = await wrapped(*args, **kwargs)
181
124
  session_id = str(uuid.uuid4().hex)
182
- span = get_current_span()
183
- if span == INVALID_SPAN:
184
- span = tracer.start_span(
185
- name=f"{to_wrap.get('object')}.{to_wrap.get('method')}"
186
- )
187
- set_span_in_context(span, get_current())
188
- _context_spans[id(context)] = span
189
- span.set_attribute("lmnr.internal.has_browser_session", True)
190
- trace_id = format(span.get_span_context().trace_id, "032x")
191
125
 
192
- async def handle_page_navigation(page):
193
- return await handle_navigation_async(page, session_id, trace_id, client)
126
+ def create_page_handler(session_id, client):
127
+ async def page_handler(page):
128
+ await start_recording_events_async(page, session_id, client)
129
+
130
+ return page_handler
194
131
 
195
- context.on("page", handle_page_navigation)
132
+ page_handler = create_page_handler(session_id, client)
133
+ context.on("page", page_handler)
196
134
  for page in context.pages:
197
- await handle_navigation_async(page, session_id, trace_id, client)
135
+ await start_recording_events_async(page, session_id, client)
136
+
198
137
  return context
199
138
 
200
139
 
201
140
  @with_tracer_and_client_wrapper
202
- def _wrap_close_browser_sync(
203
- tracer: Tracer,
204
- client: LaminarClient,
205
- to_wrap,
206
- wrapped,
207
- instance: SyncBrowser,
208
- args,
209
- kwargs,
141
+ def _wrap_bring_to_front_sync(
142
+ tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
143
+ ):
144
+ wrapped(*args, **kwargs)
145
+ take_full_snapshot(instance)
146
+
147
+
148
+ @with_tracer_and_client_wrapper
149
+ async def _wrap_bring_to_front_async(
150
+ tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
210
151
  ):
211
- global _context_spans
212
- for context in instance.contexts:
213
- key = id(context)
214
- span = _context_spans.get(key)
215
- if span:
216
- if span.is_recording():
217
- span.end()
218
- _context_spans.pop(key)
219
- return wrapped(*args, **kwargs)
152
+ await wrapped(*args, **kwargs)
153
+ await take_full_snapshot_async(instance)
220
154
 
221
155
 
222
156
  @with_tracer_and_client_wrapper
223
- async def _wrap_close_browser_async(
224
- tracer: Tracer,
225
- client: AsyncLaminarClient,
226
- to_wrap,
227
- wrapped,
228
- instance: Browser,
229
- args,
230
- kwargs,
157
+ def _wrap_browser_new_page_sync(
158
+ tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
231
159
  ):
232
- global _context_spans
233
- for context in instance.contexts:
234
- key = id(context)
235
- span = _context_spans.get(key)
236
- if span:
237
- if span.is_recording():
238
- span.end()
239
- _context_spans.pop(key)
240
- return await wrapped(*args, **kwargs)
160
+ page = wrapped(*args, **kwargs)
161
+ session_id = str(uuid.uuid4().hex)
162
+ start_recording_events_sync(page, session_id, client)
163
+ return page
164
+
165
+
166
+ @with_tracer_and_client_wrapper
167
+ async def _wrap_browser_new_page_async(
168
+ tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
169
+ ):
170
+ page = await wrapped(*args, **kwargs)
171
+ session_id = str(uuid.uuid4().hex)
172
+ await start_recording_events_async(page, session_id, client)
173
+ return page
241
174
 
242
175
 
243
176
  WRAPPED_METHODS = [
244
- {
245
- "package": "playwright.sync_api",
246
- "object": "BrowserContext",
247
- "method": "new_page",
248
- "wrapper": _wrap_new_page,
249
- },
250
- {
251
- "package": "playwright.sync_api",
252
- "object": "Browser",
253
- "method": "new_page",
254
- "wrapper": _wrap_new_page,
255
- },
256
177
  {
257
178
  "package": "playwright.sync_api",
258
179
  "object": "BrowserType",
@@ -271,12 +192,6 @@ WRAPPED_METHODS = [
271
192
  "method": "connect_over_cdp",
272
193
  "wrapper": _wrap_new_browser_sync,
273
194
  },
274
- {
275
- "package": "playwright.sync_api",
276
- "object": "Browser",
277
- "method": "close",
278
- "wrapper": _wrap_close_browser_sync,
279
- },
280
195
  {
281
196
  "package": "playwright.sync_api",
282
197
  "object": "Browser",
@@ -289,21 +204,21 @@ WRAPPED_METHODS = [
289
204
  "method": "launch_persistent_context",
290
205
  "wrapper": _wrap_new_context_sync,
291
206
  },
292
- ]
293
-
294
- WRAPPED_METHODS_ASYNC = [
295
207
  {
296
- "package": "playwright.async_api",
297
- "object": "BrowserContext",
298
- "method": "new_page",
299
- "wrapper": _wrap_new_page_async,
208
+ "package": "playwright.sync_api",
209
+ "object": "Page",
210
+ "method": "bring_to_front",
211
+ "wrapper": _wrap_bring_to_front_sync,
300
212
  },
301
213
  {
302
- "package": "playwright.async_api",
214
+ "package": "playwright.sync_api",
303
215
  "object": "Browser",
304
216
  "method": "new_page",
305
- "wrapper": _wrap_new_page_async,
217
+ "wrapper": _wrap_browser_new_page_sync,
306
218
  },
219
+ ]
220
+
221
+ WRAPPED_METHODS_ASYNC = [
307
222
  {
308
223
  "package": "playwright.async_api",
309
224
  "object": "BrowserType",
@@ -322,12 +237,6 @@ WRAPPED_METHODS_ASYNC = [
322
237
  "method": "connect_over_cdp",
323
238
  "wrapper": _wrap_new_browser_async,
324
239
  },
325
- {
326
- "package": "playwright.async_api",
327
- "object": "Browser",
328
- "method": "close",
329
- "wrapper": _wrap_close_browser_async,
330
- },
331
240
  {
332
241
  "package": "playwright.async_api",
333
242
  "object": "Browser",
@@ -340,13 +249,24 @@ WRAPPED_METHODS_ASYNC = [
340
249
  "method": "launch_persistent_context",
341
250
  "wrapper": _wrap_new_context_async,
342
251
  },
252
+ {
253
+ "package": "playwright.async_api",
254
+ "object": "Page",
255
+ "method": "bring_to_front",
256
+ "wrapper": _wrap_bring_to_front_async,
257
+ },
258
+ {
259
+ "package": "playwright.async_api",
260
+ "object": "Browser",
261
+ "method": "new_page",
262
+ "wrapper": _wrap_browser_new_page_async,
263
+ },
343
264
  ]
344
265
 
345
266
 
346
267
  class PlaywrightInstrumentor(BaseInstrumentor):
347
- def __init__(self, client: LaminarClient, async_client: AsyncLaminarClient):
268
+ def __init__(self, async_client: AsyncLaminarClient):
348
269
  super().__init__()
349
- self.client = client
350
270
  self.async_client = async_client
351
271
 
352
272
  def instrumentation_dependencies(self) -> Collection[str]:
@@ -356,6 +276,8 @@ class PlaywrightInstrumentor(BaseInstrumentor):
356
276
  tracer_provider = kwargs.get("tracer_provider")
357
277
  tracer = get_tracer(__name__, __version__, tracer_provider)
358
278
 
279
+ # Both sync and async methods use async_client because we are using
280
+ # a background asyncio loop for async sends
359
281
  for wrapped_method in WRAPPED_METHODS:
360
282
  wrap_package = wrapped_method.get("package")
361
283
  wrap_object = wrapped_method.get("object")
@@ -366,7 +288,7 @@ class PlaywrightInstrumentor(BaseInstrumentor):
366
288
  f"{wrap_object}.{wrap_method}",
367
289
  wrapped_method.get("wrapper")(
368
290
  tracer,
369
- self.client,
291
+ self.async_client,
370
292
  wrapped_method,
371
293
  ),
372
294
  )
@@ -393,13 +315,8 @@ class PlaywrightInstrumentor(BaseInstrumentor):
393
315
 
394
316
  def _uninstrument(self, **kwargs):
395
317
  # Unwrap methods
396
- global _context_spans
397
318
  for wrapped_method in WRAPPED_METHODS + WRAPPED_METHODS_ASYNC:
398
319
  wrap_package = wrapped_method.get("package")
399
320
  wrap_object = wrapped_method.get("object")
400
321
  wrap_method = wrapped_method.get("method")
401
322
  unwrap(wrap_package, f"{wrap_object}.{wrap_method}")
402
- for span in _context_spans.values():
403
- if span.is_recording():
404
- span.end()
405
- _context_spans = {}