pydoll-python 2.21.2__tar.gz → 2.21.3__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 (105) hide show
  1. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/PKG-INFO +1 -1
  2. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/web_element.py +12 -5
  3. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/interactions/iframe.py +87 -17
  4. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pyproject.toml +1 -1
  5. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/LICENSE +0 -0
  6. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/README.md +0 -0
  7. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/__init__.py +0 -0
  8. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/__init__.py +0 -0
  9. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/chromium/__init__.py +0 -0
  10. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/chromium/base.py +0 -0
  11. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/chromium/chrome.py +0 -0
  12. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/chromium/edge.py +0 -0
  13. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/interfaces.py +0 -0
  14. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/managers/__init__.py +0 -0
  15. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/managers/browser_options_manager.py +0 -0
  16. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/managers/browser_process_manager.py +0 -0
  17. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/managers/proxy_manager.py +0 -0
  18. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/managers/temp_dir_manager.py +0 -0
  19. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/options.py +0 -0
  20. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/requests/__init__.py +0 -0
  21. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/requests/har_recorder.py +0 -0
  22. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/requests/request.py +0 -0
  23. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/requests/response.py +0 -0
  24. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/browser/tab.py +0 -0
  25. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/__init__.py +0 -0
  26. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/browser_commands.py +0 -0
  27. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/dom_commands.py +0 -0
  28. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/emulation_commands.py +0 -0
  29. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/fetch_commands.py +0 -0
  30. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/input_commands.py +0 -0
  31. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/network_commands.py +0 -0
  32. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/page_commands.py +0 -0
  33. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/runtime_commands.py +0 -0
  34. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/storage_commands.py +0 -0
  35. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/commands/target_commands.py +0 -0
  36. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/connection/__init__.py +0 -0
  37. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/connection/connection_handler.py +0 -0
  38. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/connection/managers/__init__.py +0 -0
  39. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/connection/managers/commands_manager.py +0 -0
  40. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/connection/managers/events_manager.py +0 -0
  41. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/constants.py +0 -0
  42. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/decorators.py +0 -0
  43. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/__init__.py +0 -0
  44. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/mixins/__init__.py +0 -0
  45. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/mixins/find_elements_mixin.py +0 -0
  46. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/shadow_root.py +0 -0
  47. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/utils/__init__.py +0 -0
  48. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/elements/utils/selector_parser.py +0 -0
  49. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/exceptions.py +0 -0
  50. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/interactions/__init__.py +0 -0
  51. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/interactions/keyboard.py +0 -0
  52. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/interactions/mouse.py +0 -0
  53. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/interactions/scroll.py +0 -0
  54. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/interactions/utils.py +0 -0
  55. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/__init__.py +0 -0
  56. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/base.py +0 -0
  57. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/browser/__init__.py +0 -0
  58. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/browser/events.py +0 -0
  59. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/browser/methods.py +0 -0
  60. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/browser/types.py +0 -0
  61. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/debugger/types.py +0 -0
  62. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/dom/__init__.py +0 -0
  63. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/dom/events.py +0 -0
  64. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/dom/methods.py +0 -0
  65. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/dom/types.py +0 -0
  66. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/emulation/__init__.py +0 -0
  67. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/emulation/methods.py +0 -0
  68. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/emulation/types.py +0 -0
  69. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/fetch/__init__.py +0 -0
  70. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/fetch/events.py +0 -0
  71. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/fetch/methods.py +0 -0
  72. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/fetch/types.py +0 -0
  73. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/input/__init__.py +0 -0
  74. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/input/events.py +0 -0
  75. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/input/methods.py +0 -0
  76. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/input/types.py +0 -0
  77. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/io/types.py +0 -0
  78. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/network/__init__.py +0 -0
  79. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/network/events.py +0 -0
  80. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/network/har_types.py +0 -0
  81. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/network/methods.py +0 -0
  82. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/network/types.py +0 -0
  83. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/page/__init__.py +0 -0
  84. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/page/events.py +0 -0
  85. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/page/methods.py +0 -0
  86. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/page/types.py +0 -0
  87. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/runtime/__init__.py +0 -0
  88. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/runtime/events.py +0 -0
  89. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/runtime/methods.py +0 -0
  90. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/runtime/types.py +0 -0
  91. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/security/types.py +0 -0
  92. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/storage/__init__.py +0 -0
  93. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/storage/events.py +0 -0
  94. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/storage/methods.py +0 -0
  95. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/storage/types.py +0 -0
  96. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/target/__init__.py +0 -0
  97. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/target/events.py +0 -0
  98. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/target/methods.py +0 -0
  99. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/protocol/target/types.py +0 -0
  100. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/py.typed +0 -0
  101. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/utils/__init__.py +0 -0
  102. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/utils/bundle.py +0 -0
  103. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/utils/general.py +0 -0
  104. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/utils/socks5_proxy_forwarder.py +0 -0
  105. {pydoll_python-2.21.2 → pydoll_python-2.21.3}/pydoll/utils/user_agent_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydoll-python
3
- Version: 2.21.2
3
+ Version: 2.21.3
4
4
  Summary: Pydoll is a library for automating chromium-based browsers without a WebDriver, offering realistic interactions.
5
5
  License-File: LICENSE
6
6
  Author: Thalison Fernandes
@@ -943,11 +943,18 @@ class WebElement(FindElementsMixin): # noqa: PLR0904
943
943
  return response['result']['result'].get('value', '')
944
944
 
945
945
  def _apply_routing_from_context(self) -> None:
946
- """Apply routing attributes from iframe context."""
947
- if hasattr(self, '_routing_session_handler'):
948
- delattr(self, '_routing_session_handler')
949
- if hasattr(self, '_routing_session_id'):
950
- delattr(self, '_routing_session_id')
946
+ """Apply routing attributes from iframe context.
947
+
948
+ After iframe context resolution, commands targeting the *content* of
949
+ the iframe should route through ``_iframe_context`` (handled by
950
+ ``_resolve_routing`` which prioritises ``_iframe_context`` over
951
+ ``_routing_session_*``).
952
+
953
+ The ``_routing_session_handler`` / ``_routing_session_id`` attributes
954
+ must be preserved: they identify the parent OOPIF session where the
955
+ ``<iframe>`` *element itself* lives. The resolver needs them to
956
+ re-describe the element on subsequent re-resolutions.
957
+ """
951
958
 
952
959
  async def _click_option_tag(self):
953
960
  """Specialized method for clicking <option> elements in dropdowns."""
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Iterable, Optional
7
7
  from pydoll.commands import DomCommands, PageCommands, RuntimeCommands, TargetCommands
8
8
  from pydoll.connection import ConnectionHandler
9
9
  from pydoll.exceptions import InvalidIFrame
10
- from pydoll.protocol.dom.methods import GetFrameOwnerResponse
10
+ from pydoll.protocol.dom.methods import DescribeNodeResponse, GetFrameOwnerResponse
11
11
  from pydoll.protocol.dom.types import Node
12
12
  from pydoll.protocol.page.methods import CreateIsolatedWorldResponse, GetFrameTreeResponse
13
13
  from pydoll.protocol.page.types import Frame, FrameTree
@@ -49,10 +49,10 @@ class IFrameContextResolver:
49
49
  Raises:
50
50
  InvalidIFrame: If unable to resolve the iframe context.
51
51
  """
52
- node_info = await self._element._describe_node(object_id=self._element._object_id)
53
52
  base_handler, base_session_id = self._get_base_session()
54
- frame_id, document_url, parent_frame_id, backend_node_id = self._extract_frame_metadata(
55
- node_info
53
+ node_info = await self._describe_element_node(base_handler, base_session_id)
54
+ frame_id, document_url, content_frame_id, backend_node_id = (
55
+ self._extract_frame_metadata(node_info)
56
56
  )
57
57
 
58
58
  if not frame_id and backend_node_id is not None:
@@ -61,7 +61,12 @@ class IFrameContextResolver:
61
61
  )
62
62
 
63
63
  session_handler, session_id, frame_id, document_url = await self._resolve_oopif_if_needed(
64
- frame_id, parent_frame_id, backend_node_id, document_url
64
+ frame_id,
65
+ content_frame_id,
66
+ backend_node_id,
67
+ current_document_url=document_url,
68
+ base_handler=base_handler,
69
+ base_session_id=base_session_id,
65
70
  )
66
71
 
67
72
  if not frame_id:
@@ -95,13 +100,41 @@ class IFrameContextResolver:
95
100
  session_id = getattr(self._element, '_routing_session_id', None)
96
101
  return handler, session_id
97
102
 
103
+ async def _describe_element_node(
104
+ self,
105
+ handler: ConnectionHandler,
106
+ session_id: Optional[str],
107
+ ) -> Node:
108
+ """Describe the iframe element using the given handler/session.
109
+
110
+ This bypasses ``_resolve_routing()`` which, after a previous
111
+ resolution, may return the iframe *content* session instead of
112
+ the parent session where the element actually lives.
113
+ """
114
+ command = DomCommands.describe_node(object_id=self._element._object_id)
115
+ if session_id:
116
+ command['sessionId'] = session_id
117
+ response: DescribeNodeResponse = await handler.execute_command(command)
118
+ if 'error' in response:
119
+ return {}
120
+ return response.get('result', {}).get('node', {})
121
+
98
122
  @staticmethod
99
123
  def _extract_frame_metadata(
100
124
  node_info: Node,
101
125
  ) -> tuple[Optional[str], Optional[str], Optional[str], Optional[int]]:
102
- """Extract iframe-related metadata from DOM node info."""
126
+ """Extract iframe-related metadata from DOM node info.
127
+
128
+ Returns:
129
+ Tuple of (frame_id, document_url, content_frame_id, backend_node_id).
130
+ ``content_frame_id`` is the frame ID of the frame *created* by the
131
+ ``<iframe>`` element (``node_info['frameId']`` on frame-owner
132
+ elements). For same-origin iframes it equals
133
+ ``contentDocument.frameId``; for OOPIFs ``contentDocument`` is
134
+ absent but ``content_frame_id`` is still set by the browser.
135
+ """
103
136
  content_document = node_info.get('contentDocument') or {}
104
- parent_frame_id = node_info.get('frameId')
137
+ content_frame_id = node_info.get('frameId')
105
138
  backend_node_id = node_info.get('backendNodeId')
106
139
  frame_id = content_document.get('frameId')
107
140
  document_url = (
@@ -110,7 +143,7 @@ class IFrameContextResolver:
110
143
  or node_info.get('documentURL')
111
144
  or node_info.get('baseURL')
112
145
  )
113
- return frame_id, document_url, parent_frame_id, backend_node_id
146
+ return frame_id, document_url, content_frame_id, backend_node_id
114
147
 
115
148
  async def _resolve_frame_by_owner(
116
149
  self,
@@ -184,12 +217,14 @@ class IFrameContextResolver:
184
217
  async def _resolve_oopif_if_needed(
185
218
  self,
186
219
  current_frame_id: Optional[str],
187
- parent_frame_id: Optional[str],
220
+ content_frame_id: Optional[str],
188
221
  backend_node_id: Optional[int],
189
222
  current_document_url: Optional[str],
223
+ base_handler: Optional[ConnectionHandler] = None,
224
+ base_session_id: Optional[str] = None,
190
225
  ) -> tuple[Optional[ConnectionHandler], Optional[str], Optional[str], Optional[str]]:
191
226
  """Resolve OOPIF and routing when needed."""
192
- if not parent_frame_id or (current_frame_id and backend_node_id is None):
227
+ if not content_frame_id or (current_frame_id and backend_node_id is None):
193
228
  return None, None, current_frame_id, current_document_url
194
229
 
195
230
  (
@@ -197,7 +232,9 @@ class IFrameContextResolver:
197
232
  session_id,
198
233
  resolved_frame_id,
199
234
  resolved_url,
200
- ) = await self._resolve_oopif_by_parent(parent_frame_id, backend_node_id)
235
+ ) = await self._resolve_oopif_by_parent(
236
+ content_frame_id, backend_node_id, base_handler, base_session_id
237
+ )
201
238
 
202
239
  if session_handler and session_id and resolved_url:
203
240
  return (
@@ -216,10 +253,24 @@ class IFrameContextResolver:
216
253
 
217
254
  async def _resolve_oopif_by_parent(
218
255
  self,
219
- parent_frame_id: str,
256
+ content_frame_id: str,
220
257
  backend_node_id: Optional[int],
258
+ base_handler: Optional[ConnectionHandler] = None,
259
+ base_session_id: Optional[str] = None,
221
260
  ) -> tuple[Optional[ConnectionHandler], Optional[str], Optional[str], Optional[str]]:
222
- """Resolve out-of-process iframe using parent frame id."""
261
+ """Resolve out-of-process iframe using content frame id.
262
+
263
+ ``content_frame_id`` is the frame ID of the frame *created* by the
264
+ ``<iframe>`` element (obtained from ``DOM.describeNode``'s
265
+ ``node.frameId``). For OOPIF targets the root frame of the target
266
+ shares this ID, so we can match directly without needing
267
+ ``DOM.getFrameOwner``.
268
+
269
+ When a direct frame-ID match is not possible (e.g. nested sub-frames
270
+ inside the OOPIF), the method falls back to ``DOM.getFrameOwner``
271
+ using the routing handler/session that has DOM visibility into the
272
+ parent context.
273
+ """
223
274
  browser_handler = ConnectionHandler(
224
275
  connection_port=self._element._connection_handler._connection_port
225
276
  )
@@ -228,11 +279,18 @@ class IFrameContextResolver:
228
279
  )
229
280
  target_infos = targets_response.get('result', {}).get('targetInfos', [])
230
281
 
282
+ # The handler/session that can resolve DOM.getFrameOwner for the
283
+ # element's context. When the <iframe> lives inside a nested OOPIF
284
+ # the Tab-level handler has no visibility; we must route through the
285
+ # session that originally found the element.
286
+ owner_handler = base_handler or self._element._connection_handler
287
+ owner_session_id = base_session_id
288
+
231
289
  direct_children = [
232
290
  target_info
233
291
  for target_info in target_infos
234
292
  if target_info.get('type') in {'iframe', 'page'}
235
- and target_info.get('parentFrameId') == parent_frame_id
293
+ and target_info.get('parentFrameId') == content_frame_id
236
294
  ]
237
295
 
238
296
  is_single_child = len(direct_children) == 1
@@ -258,7 +316,7 @@ class IFrameContextResolver:
258
316
 
259
317
  if root_frame_id and backend_node_id is not None:
260
318
  owner_backend_id = await self._owner_backend_for(
261
- self._element._connection_handler, None, root_frame_id
319
+ owner_handler, owner_session_id, root_frame_id
262
320
  )
263
321
  if owner_backend_id == backend_node_id:
264
322
  return (
@@ -284,9 +342,21 @@ class IFrameContextResolver:
284
342
  root_frame = (frame_tree or {}).get('frame', {})
285
343
  root_frame_id = root_frame.get('id', '')
286
344
 
345
+ # Direct match: the <iframe> element's frameId (content_frame_id)
346
+ # equals this target's root frame ID. This handles nested OOPIFs
347
+ # where DOM.getFrameOwner cannot be resolved through the main
348
+ # page handler.
349
+ if root_frame_id and root_frame_id == content_frame_id:
350
+ return (
351
+ browser_handler,
352
+ attached_session_id,
353
+ root_frame_id,
354
+ root_frame.get('url'),
355
+ )
356
+
287
357
  if root_frame_id and backend_node_id is not None:
288
358
  owner_backend_id = await self._owner_backend_for(
289
- self._element._connection_handler, None, root_frame_id
359
+ owner_handler, owner_session_id, root_frame_id
290
360
  )
291
361
  if owner_backend_id == backend_node_id:
292
362
  return (
@@ -296,7 +366,7 @@ class IFrameContextResolver:
296
366
  root_frame.get('url'),
297
367
  )
298
368
 
299
- child_frame_id = self._find_child_by_parent(frame_tree, parent_frame_id)
369
+ child_frame_id = self._find_child_by_parent(frame_tree, content_frame_id)
300
370
  if child_frame_id:
301
371
  return browser_handler, attached_session_id, child_frame_id, None
302
372
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pydoll-python"
3
- version = "2.21.2"
3
+ version = "2.21.3"
4
4
  description = "Pydoll is a library for automating chromium-based browsers without a WebDriver, offering realistic interactions."
5
5
  authors = ["Thalison Fernandes <thalissfernandes99@gmail.com>"]
6
6
  readme = "README.md"
File without changes
File without changes