pydoll-python 2.8.1__tar.gz → 2.8.2__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.
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/PKG-INFO +1 -1
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/chromium/base.py +112 -4
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/tab.py +33 -3
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/elements/mixins/find_elements_mixin.py +5 -5
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/exceptions.py +6 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pyproject.toml +1 -1
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/LICENSE +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/README.md +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/chromium/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/chromium/chrome.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/chromium/edge.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/interfaces.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/browser_options_manager.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/browser_process_manager.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/proxy_manager.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/temp_dir_manager.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/options.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/requests/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/requests/request.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/requests/response.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/browser_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/dom_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/fetch_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/input_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/network_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/page_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/runtime_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/storage_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/commands/target_commands.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/connection/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/connection/connection_handler.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/connection/managers/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/connection/managers/commands_manager.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/connection/managers/events_manager.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/constants.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/elements/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/elements/mixins/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/elements/web_element.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/base.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/browser/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/browser/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/browser/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/browser/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/debugger/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/dom/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/dom/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/dom/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/dom/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/emulation/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/fetch/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/fetch/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/fetch/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/fetch/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/input/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/input/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/input/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/input/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/io/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/network/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/network/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/network/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/network/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/page/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/page/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/page/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/page/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/runtime/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/runtime/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/runtime/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/runtime/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/security/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/storage/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/storage/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/storage/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/storage/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/target/__init__.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/target/events.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/target/methods.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/protocol/target/types.py +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/py.typed +0 -0
- {pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/utils.py +0 -0
|
@@ -9,6 +9,7 @@ from functools import partial
|
|
|
9
9
|
from random import randint
|
|
10
10
|
from tempfile import TemporaryDirectory
|
|
11
11
|
from typing import Any, Awaitable, Callable, Optional, overload
|
|
12
|
+
from urllib.parse import urlsplit, urlunsplit
|
|
12
13
|
|
|
13
14
|
from pydoll.browser.interfaces import BrowserOptionsManager
|
|
14
15
|
from pydoll.browser.managers import (
|
|
@@ -93,6 +94,7 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
93
94
|
self._connection_handler = ConnectionHandler(self._connection_port)
|
|
94
95
|
self._backup_preferences_dir = ''
|
|
95
96
|
self._tabs_opened: dict[str, Tab] = {}
|
|
97
|
+
self._context_proxy_auth: dict[str, tuple[str, str]] = {}
|
|
96
98
|
|
|
97
99
|
async def __aenter__(self) -> 'Browser':
|
|
98
100
|
"""Async context manager entry."""
|
|
@@ -203,13 +205,22 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
203
205
|
Returns:
|
|
204
206
|
Browser context ID for use with other methods.
|
|
205
207
|
"""
|
|
208
|
+
# If proxy_server contains credentials, strip them and store per-context auth
|
|
209
|
+
sanitized_proxy = proxy_server
|
|
210
|
+
extracted_auth: Optional[tuple[str, str]] = None
|
|
211
|
+
if proxy_server:
|
|
212
|
+
sanitized_proxy, extracted_auth = self._sanitize_proxy_and_extract_auth(proxy_server)
|
|
213
|
+
|
|
206
214
|
response: CreateBrowserContextResponse = await self._execute_command(
|
|
207
215
|
TargetCommands.create_browser_context(
|
|
208
|
-
proxy_server=
|
|
216
|
+
proxy_server=sanitized_proxy,
|
|
209
217
|
proxy_bypass_list=proxy_bypass_list,
|
|
210
218
|
)
|
|
211
219
|
)
|
|
212
|
-
|
|
220
|
+
context_id = response['result']['browserContextId']
|
|
221
|
+
if extracted_auth:
|
|
222
|
+
self._context_proxy_auth[context_id] = extracted_auth
|
|
223
|
+
return context_id
|
|
213
224
|
|
|
214
225
|
async def delete_browser_context(self, browser_context_id: str):
|
|
215
226
|
"""
|
|
@@ -251,8 +262,8 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
251
262
|
target_id = response['result']['targetId']
|
|
252
263
|
tab = Tab(self, **self._get_tab_kwargs(target_id, browser_context_id))
|
|
253
264
|
self._tabs_opened[target_id] = tab
|
|
254
|
-
|
|
255
|
-
|
|
265
|
+
await self._setup_context_proxy_auth_for_tab(tab, browser_context_id)
|
|
266
|
+
if url: await tab.go_to(url)
|
|
256
267
|
return tab
|
|
257
268
|
|
|
258
269
|
async def get_targets(self) -> list[TargetInfo]:
|
|
@@ -577,6 +588,60 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
577
588
|
await self.disable_fetch_events()
|
|
578
589
|
return response
|
|
579
590
|
|
|
591
|
+
@staticmethod
|
|
592
|
+
async def _tab_continue_request_callback(event: RequestPausedEvent, tab: Tab):
|
|
593
|
+
"""Internal callback to continue paused requests at Tab level."""
|
|
594
|
+
request_id = event['params']['requestId']
|
|
595
|
+
return await tab.continue_request(request_id)
|
|
596
|
+
|
|
597
|
+
@staticmethod
|
|
598
|
+
async def _tab_continue_request_with_auth_callback(
|
|
599
|
+
event: RequestPausedEvent,
|
|
600
|
+
tab: Tab,
|
|
601
|
+
proxy_username: Optional[str],
|
|
602
|
+
proxy_password: Optional[str],
|
|
603
|
+
):
|
|
604
|
+
"""Internal callback for proxy/server authentication at Tab level."""
|
|
605
|
+
request_id = event['params']['requestId']
|
|
606
|
+
response: Response = await tab.continue_with_auth(
|
|
607
|
+
request_id=request_id,
|
|
608
|
+
auth_challenge_response=AuthChallengeResponseType.PROVIDE_CREDENTIALS,
|
|
609
|
+
proxy_username=proxy_username,
|
|
610
|
+
proxy_password=proxy_password,
|
|
611
|
+
)
|
|
612
|
+
await tab.disable_fetch_events()
|
|
613
|
+
return response
|
|
614
|
+
|
|
615
|
+
async def _setup_context_proxy_auth_for_tab(
|
|
616
|
+
self, tab: Tab, browser_context_id: Optional[str]
|
|
617
|
+
) -> None:
|
|
618
|
+
"""Enable proxy auth handling for a Tab if its context has credentials stored."""
|
|
619
|
+
if not browser_context_id:
|
|
620
|
+
return
|
|
621
|
+
creds = self._context_proxy_auth.get(browser_context_id)
|
|
622
|
+
if not creds:
|
|
623
|
+
return
|
|
624
|
+
username, password = creds
|
|
625
|
+
await tab.enable_fetch_events(handle_auth=True)
|
|
626
|
+
await tab.on(
|
|
627
|
+
FetchEvent.REQUEST_PAUSED,
|
|
628
|
+
partial(
|
|
629
|
+
self._tab_continue_request_callback,
|
|
630
|
+
tab=tab,
|
|
631
|
+
),
|
|
632
|
+
temporary=True,
|
|
633
|
+
)
|
|
634
|
+
await tab.on(
|
|
635
|
+
FetchEvent.AUTH_REQUIRED,
|
|
636
|
+
partial(
|
|
637
|
+
self._tab_continue_request_with_auth_callback,
|
|
638
|
+
tab=tab,
|
|
639
|
+
proxy_username=username,
|
|
640
|
+
proxy_password=password,
|
|
641
|
+
),
|
|
642
|
+
temporary=True,
|
|
643
|
+
)
|
|
644
|
+
|
|
580
645
|
async def _verify_browser_running(self):
|
|
581
646
|
"""
|
|
582
647
|
Verify browser started successfully.
|
|
@@ -763,6 +828,49 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
763
828
|
ws_domain = '/'.join(self._ws_address.split('/')[:3])
|
|
764
829
|
return f'{ws_domain}/devtools/page/{tab_id}'
|
|
765
830
|
|
|
831
|
+
@staticmethod
|
|
832
|
+
def _sanitize_proxy_and_extract_auth(
|
|
833
|
+
proxy_server: str,
|
|
834
|
+
) -> tuple[str, Optional[tuple[str, str]]]:
|
|
835
|
+
"""Strip credentials from a proxy URL and return sanitized URL plus (user, pass).
|
|
836
|
+
|
|
837
|
+
Accepts inputs like:
|
|
838
|
+
- username:password@host:port
|
|
839
|
+
- http://username:password@host:port
|
|
840
|
+
- socks5://username:password@host:port
|
|
841
|
+
- host:port (no credentials)
|
|
842
|
+
Returns a (sanitized_proxy, (user, pass) | None).
|
|
843
|
+
Ensures scheme is present in the sanitized URL (defaults to http).
|
|
844
|
+
"""
|
|
845
|
+
base = proxy_server if '://' in proxy_server else f'http://{proxy_server}'
|
|
846
|
+
parts = urlsplit(base)
|
|
847
|
+
netloc = parts.netloc
|
|
848
|
+
creds: Optional[tuple[str, str]] = None
|
|
849
|
+
if '@' in netloc:
|
|
850
|
+
cred_part, host_part = netloc.split('@', 1)
|
|
851
|
+
if ':' in cred_part:
|
|
852
|
+
user, pwd = cred_part.split(':', 1)
|
|
853
|
+
else:
|
|
854
|
+
user, pwd = cred_part, ''
|
|
855
|
+
creds = (user, pwd)
|
|
856
|
+
sanitized = urlunsplit((
|
|
857
|
+
parts.scheme,
|
|
858
|
+
host_part,
|
|
859
|
+
parts.path,
|
|
860
|
+
parts.query,
|
|
861
|
+
parts.fragment,
|
|
862
|
+
))
|
|
863
|
+
else:
|
|
864
|
+
# No creds; ensure scheme
|
|
865
|
+
sanitized = urlunsplit((
|
|
866
|
+
parts.scheme,
|
|
867
|
+
parts.netloc,
|
|
868
|
+
parts.path,
|
|
869
|
+
parts.query,
|
|
870
|
+
parts.fragment,
|
|
871
|
+
))
|
|
872
|
+
return sanitized, creds
|
|
873
|
+
|
|
766
874
|
@abstractmethod
|
|
767
875
|
def _get_default_binary_location(self) -> str:
|
|
768
876
|
"""Get default browser executable path (implemented by subclasses)."""
|
|
@@ -46,6 +46,7 @@ from pydoll.exceptions import (
|
|
|
46
46
|
NoDialogPresent,
|
|
47
47
|
NotAnIFrame,
|
|
48
48
|
PageLoadTimeout,
|
|
49
|
+
TopLevelTargetRequired,
|
|
49
50
|
WaitElementTimeout,
|
|
50
51
|
)
|
|
51
52
|
from pydoll.protocol.base import EmptyResponse, Response
|
|
@@ -55,7 +56,7 @@ from pydoll.protocol.browser.events import (
|
|
|
55
56
|
DownloadWillBeginEvent,
|
|
56
57
|
)
|
|
57
58
|
from pydoll.protocol.browser.types import DownloadBehavior, DownloadProgressState
|
|
58
|
-
from pydoll.protocol.fetch.types import HeaderEntry, RequestStage
|
|
59
|
+
from pydoll.protocol.fetch.types import AuthChallengeResponseType, HeaderEntry, RequestStage
|
|
59
60
|
from pydoll.protocol.network.events import RequestWillBeSentEvent
|
|
60
61
|
from pydoll.protocol.network.types import (
|
|
61
62
|
Cookie,
|
|
@@ -252,7 +253,7 @@ class Tab(FindElementsMixin):
|
|
|
252
253
|
async def enable_auto_solve_cloudflare_captcha(
|
|
253
254
|
self,
|
|
254
255
|
custom_selector: Optional[tuple[By, str]] = None,
|
|
255
|
-
time_before_click: int =
|
|
256
|
+
time_before_click: int = 5,
|
|
256
257
|
time_to_wait_captcha: int = 5,
|
|
257
258
|
):
|
|
258
259
|
"""
|
|
@@ -527,7 +528,15 @@ class Tab(FindElementsMixin):
|
|
|
527
528
|
capture_beyond_viewport=beyond_viewport,
|
|
528
529
|
)
|
|
529
530
|
)
|
|
530
|
-
|
|
531
|
+
|
|
532
|
+
try:
|
|
533
|
+
screenshot_data = response['result']['data']
|
|
534
|
+
except KeyError:
|
|
535
|
+
raise TopLevelTargetRequired(
|
|
536
|
+
'Command can only be executed on top-level targets. Please use '
|
|
537
|
+
'take_screenshot method on the WebElement object instead.'
|
|
538
|
+
)
|
|
539
|
+
|
|
531
540
|
if as_base64:
|
|
532
541
|
return screenshot_data
|
|
533
542
|
|
|
@@ -700,6 +709,27 @@ class Tab(FindElementsMixin):
|
|
|
700
709
|
)
|
|
701
710
|
)
|
|
702
711
|
|
|
712
|
+
async def continue_with_auth(
|
|
713
|
+
self,
|
|
714
|
+
request_id: str,
|
|
715
|
+
auth_challenge_response: AuthChallengeResponseType,
|
|
716
|
+
proxy_username: Optional[str] = None,
|
|
717
|
+
proxy_password: Optional[str] = None,
|
|
718
|
+
):
|
|
719
|
+
"""Continue a paused request replying to an authentication challenge.
|
|
720
|
+
|
|
721
|
+
Useful for proxy auth (407) or server auth (401) when Fetch is enabled
|
|
722
|
+
with handle_auth=True.
|
|
723
|
+
"""
|
|
724
|
+
return await self._execute_command(
|
|
725
|
+
FetchCommands.continue_request_with_auth(
|
|
726
|
+
request_id=request_id,
|
|
727
|
+
auth_challenge_response=auth_challenge_response,
|
|
728
|
+
proxy_username=proxy_username,
|
|
729
|
+
proxy_password=proxy_password,
|
|
730
|
+
)
|
|
731
|
+
)
|
|
732
|
+
|
|
703
733
|
@asynccontextmanager
|
|
704
734
|
async def expect_file_chooser(
|
|
705
735
|
self, files: Union[str, Path, list[Union[str, Path]]]
|
|
@@ -59,7 +59,7 @@ class FindElementsMixin:
|
|
|
59
59
|
timeout: int = ...,
|
|
60
60
|
find_all: Literal[False] = False,
|
|
61
61
|
raise_exc: Literal[True] = True,
|
|
62
|
-
**attributes
|
|
62
|
+
**attributes,
|
|
63
63
|
) -> 'WebElement': ...
|
|
64
64
|
|
|
65
65
|
@overload
|
|
@@ -73,7 +73,7 @@ class FindElementsMixin:
|
|
|
73
73
|
timeout: int = ...,
|
|
74
74
|
find_all: Literal[True] = True,
|
|
75
75
|
raise_exc: Literal[True] = True,
|
|
76
|
-
**attributes
|
|
76
|
+
**attributes,
|
|
77
77
|
) -> list['WebElement']: ...
|
|
78
78
|
|
|
79
79
|
@overload
|
|
@@ -87,7 +87,7 @@ class FindElementsMixin:
|
|
|
87
87
|
timeout: int = ...,
|
|
88
88
|
find_all: Literal[True] = True,
|
|
89
89
|
raise_exc: Literal[False] = False,
|
|
90
|
-
**attributes
|
|
90
|
+
**attributes,
|
|
91
91
|
) -> Optional[list['WebElement']]: ...
|
|
92
92
|
|
|
93
93
|
@overload
|
|
@@ -101,7 +101,7 @@ class FindElementsMixin:
|
|
|
101
101
|
timeout: int = ...,
|
|
102
102
|
find_all: Literal[False] = False,
|
|
103
103
|
raise_exc: Literal[False] = False,
|
|
104
|
-
**attributes
|
|
104
|
+
**attributes,
|
|
105
105
|
) -> Optional['WebElement']: ...
|
|
106
106
|
|
|
107
107
|
@overload
|
|
@@ -115,7 +115,7 @@ class FindElementsMixin:
|
|
|
115
115
|
timeout: int = ...,
|
|
116
116
|
find_all: bool = ...,
|
|
117
117
|
raise_exc: bool = ...,
|
|
118
|
-
**attributes
|
|
118
|
+
**attributes,
|
|
119
119
|
) -> Union['WebElement', list['WebElement'], None]: ...
|
|
120
120
|
|
|
121
121
|
async def find(
|
|
@@ -103,6 +103,12 @@ class ProtocolException(PydollException):
|
|
|
103
103
|
message = 'A protocol error occurred'
|
|
104
104
|
|
|
105
105
|
|
|
106
|
+
class TopLevelTargetRequired(ProtocolException):
|
|
107
|
+
"""Raised when a command can only be executed on top-level targets."""
|
|
108
|
+
|
|
109
|
+
message = 'Command can only be executed on top-level targets.'
|
|
110
|
+
|
|
111
|
+
|
|
106
112
|
class InvalidCommand(ProtocolException):
|
|
107
113
|
"""Raised when an invalid command is sent to the browser."""
|
|
108
114
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pydoll-python"
|
|
3
|
-
version = "2.8.
|
|
3
|
+
version = "2.8.2"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/browser_options_manager.py
RENAMED
|
File without changes
|
{pydoll_python-2.8.1 → pydoll_python-2.8.2}/pydoll/browser/managers/browser_process_manager.py
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|