osn-selenium 1.0.0__py3-none-any.whl → 1.1.0__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.
- osn_selenium/_base_models.py +41 -0
- osn_selenium/_cdp_import.py +253 -0
- osn_selenium/abstract/executors/cdp.py +63 -0
- osn_selenium/browsers_handler/models.py +1 -1
- osn_selenium/dev_tools/_decorators.py +19 -10
- osn_selenium/dev_tools/_typehints.py +5 -2
- osn_selenium/dev_tools/_wrappers.py +0 -3
- osn_selenium/dev_tools/domains/__init__.py +2 -2
- osn_selenium/dev_tools/domains/abstract.py +1 -1
- osn_selenium/dev_tools/domains/fetch.py +1 -1
- osn_selenium/dev_tools/domains_default/fetch.py +1 -1
- osn_selenium/dev_tools/filters.py +1 -1
- osn_selenium/dev_tools/logger/main.py +0 -12
- osn_selenium/dev_tools/logger/models.py +1 -1
- osn_selenium/dev_tools/logger/target.py +42 -22
- osn_selenium/dev_tools/manager/base.py +0 -23
- osn_selenium/dev_tools/manager/lifecycle.py +1 -1
- osn_selenium/dev_tools/models.py +1 -1
- osn_selenium/dev_tools/settings.py +5 -1
- osn_selenium/dev_tools/target/base.py +12 -23
- osn_selenium/dev_tools/target/lifecycle.py +6 -1
- osn_selenium/dev_tools/target/logging.py +10 -2
- osn_selenium/exceptions/dependencies.py +60 -0
- osn_selenium/executors/sync/cdp.py +100 -0
- osn_selenium/executors/trio_threads/cdp.py +104 -0
- osn_selenium/executors/trio_threads/javascript.py +1 -1
- osn_selenium/executors/unified/javascript.py +0 -4
- osn_selenium/flags/base.py +1 -9
- osn_selenium/flags/blink.py +0 -6
- osn_selenium/flags/models/base.py +4 -4
- osn_selenium/flags/models/blink.py +1 -1
- osn_selenium/flags/models/values.py +1 -1
- osn_selenium/instances/sync/action_chains/__init__.py +6 -0
- osn_selenium/instances/sync/shadow_root.py +30 -8
- osn_selenium/instances/trio_threads/action_chains/__init__.py +6 -0
- osn_selenium/instances/trio_threads/action_chains/base.py +1 -1
- osn_selenium/instances/trio_threads/alert.py +1 -1
- osn_selenium/instances/trio_threads/browser.py +1 -1
- osn_selenium/instances/trio_threads/browsing_context.py +1 -1
- osn_selenium/instances/trio_threads/dialog.py +1 -1
- osn_selenium/instances/trio_threads/fedcm.py +1 -1
- osn_selenium/instances/trio_threads/mobile.py +1 -1
- osn_selenium/instances/trio_threads/network.py +1 -1
- osn_selenium/instances/trio_threads/permissions.py +1 -1
- osn_selenium/instances/trio_threads/script.py +1 -1
- osn_selenium/instances/trio_threads/shadow_root.py +46 -15
- osn_selenium/instances/trio_threads/storage.py +1 -1
- osn_selenium/instances/trio_threads/switch_to.py +1 -1
- osn_selenium/instances/trio_threads/web_driver_wait.py +1 -1
- osn_selenium/instances/trio_threads/web_element.py +1 -1
- osn_selenium/instances/trio_threads/web_extension.py +1 -1
- osn_selenium/javascript/fingerprint/__init__.py +1 -1
- osn_selenium/javascript/fingerprint/registry/models.py +1 -1
- osn_selenium/javascript/fingerprint/spoof/core_rules.py +1 -1
- osn_selenium/javascript/fingerprint/spoof/noise.py +1 -1
- osn_selenium/javascript/models.py +1 -1
- osn_selenium/models.py +2 -47
- osn_selenium/trio_threads_mixin.py +159 -0
- osn_selenium/webdrivers/_args_helpers.py +2 -2
- osn_selenium/webdrivers/_bridges.py +2 -2
- osn_selenium/webdrivers/_executable_tables/models.py +1 -1
- osn_selenium/webdrivers/sync/blink/__init__.py +11 -1
- osn_selenium/webdrivers/sync/blink/base.py +13 -1
- osn_selenium/webdrivers/sync/chrome/__init__.py +36 -1
- osn_selenium/webdrivers/sync/chrome/base.py +13 -1
- osn_selenium/webdrivers/sync/core/__init__.py +10 -1
- osn_selenium/webdrivers/sync/core/base.py +16 -8
- osn_selenium/webdrivers/sync/edge/__init__.py +36 -1
- osn_selenium/webdrivers/sync/edge/base.py +13 -1
- osn_selenium/webdrivers/sync/yandex/__init__.py +36 -1
- osn_selenium/webdrivers/sync/yandex/base.py +13 -1
- osn_selenium/webdrivers/trio_threads/blink/__init__.py +11 -1
- osn_selenium/webdrivers/trio_threads/blink/base.py +11 -1
- osn_selenium/webdrivers/trio_threads/blink/casting.py +1 -1
- osn_selenium/webdrivers/trio_threads/blink/features.py +1 -1
- osn_selenium/webdrivers/trio_threads/blink/logging.py +1 -1
- osn_selenium/webdrivers/trio_threads/blink/network.py +1 -1
- osn_selenium/webdrivers/trio_threads/chrome/__init__.py +34 -1
- osn_selenium/webdrivers/trio_threads/chrome/base.py +14 -2
- osn_selenium/webdrivers/trio_threads/core/__init__.py +10 -4
- osn_selenium/webdrivers/trio_threads/core/actions.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/auth.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/base.py +15 -7
- osn_selenium/webdrivers/trio_threads/core/capture.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/comonents.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/devtools.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/element.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/file.py +2 -2
- osn_selenium/webdrivers/trio_threads/core/lifecycle.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/navigation.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/script.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/settings.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/storage.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/timeouts.py +1 -1
- osn_selenium/webdrivers/trio_threads/core/window.py +3 -3
- osn_selenium/webdrivers/trio_threads/edge/__init__.py +34 -1
- osn_selenium/webdrivers/trio_threads/edge/base.py +14 -2
- osn_selenium/webdrivers/trio_threads/yandex/__init__.py +34 -1
- osn_selenium/webdrivers/trio_threads/yandex/base.py +14 -2
- osn_selenium/webdrivers/unified/blink/base.py +5 -1
- osn_selenium/webdrivers/unified/chrome/base.py +5 -1
- osn_selenium/webdrivers/unified/core/base.py +9 -2
- osn_selenium/webdrivers/unified/edge/base.py +5 -1
- osn_selenium/webdrivers/unified/yandex/base.py +5 -1
- {osn_selenium-1.0.0.dist-info → osn_selenium-1.1.0.dist-info}/METADATA +22 -9
- {osn_selenium-1.0.0.dist-info → osn_selenium-1.1.0.dist-info}/RECORD +108 -101
- {osn_selenium-1.0.0.dist-info → osn_selenium-1.1.0.dist-info}/WHEEL +1 -1
- {osn_selenium-1.0.0.dist-info → osn_selenium-1.1.0.dist-info}/top_level.txt +0 -0
osn_selenium/dev_tools/models.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
from pydantic import Field
|
|
3
|
-
from osn_selenium.
|
|
3
|
+
from osn_selenium._base_models import DictModel
|
|
4
4
|
from osn_selenium.dev_tools.filters import TargetFilter
|
|
5
5
|
from osn_selenium.dev_tools.domains import DomainsSettings
|
|
6
6
|
from typing import (
|
|
@@ -39,6 +39,7 @@ class FingerprintLoggerSettings(DictModel):
|
|
|
39
39
|
Defaults to "exclude".
|
|
40
40
|
category_filter (Optional[Union[str, Sequence[str]]]): Specific categories to filter.
|
|
41
41
|
Defaults to None.
|
|
42
|
+
send_wait (bool): Whether to wait for the log to be sent. Defaults to False.
|
|
42
43
|
"""
|
|
43
44
|
|
|
44
45
|
buffer_size: int = 100
|
|
@@ -51,6 +52,7 @@ class FingerprintLoggerSettings(DictModel):
|
|
|
51
52
|
] = None
|
|
52
53
|
category_filter_mode: Literal["exclude", "include"] = "exclude"
|
|
53
54
|
category_filter: Optional[Union[str, Sequence[str]]] = None
|
|
55
|
+
send_wait: bool = False
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
class CDPLoggerSettings(DictModel):
|
|
@@ -73,6 +75,7 @@ class CDPLoggerSettings(DictModel):
|
|
|
73
75
|
target_type_filter (Optional[Union[str, Sequence[str]]]):
|
|
74
76
|
A single target type string or a sequence of target type strings to filter by.
|
|
75
77
|
Used in conjunction with `target_type_filter_mode`. Defaults to None.
|
|
78
|
+
send_wait (bool): Whether to wait for the log to be sent. Defaults to False.
|
|
76
79
|
"""
|
|
77
80
|
|
|
78
81
|
buffer_size: int = 100
|
|
@@ -80,6 +83,7 @@ class CDPLoggerSettings(DictModel):
|
|
|
80
83
|
log_level_filter: Optional[Union[CDP_LOG_LEVELS_TYPEHINT, Sequence[CDP_LOG_LEVELS_TYPEHINT]]] = None
|
|
81
84
|
target_type_filter_mode: Literal["exclude", "include"] = "exclude"
|
|
82
85
|
target_type_filter: Optional[Union[str, Sequence[str]]] = None
|
|
86
|
+
send_wait: bool = False
|
|
83
87
|
|
|
84
88
|
|
|
85
89
|
class LoggerSettings(DictModel):
|
|
@@ -50,29 +50,6 @@ class BaseMixin:
|
|
|
50
50
|
about_to_stop_event (trio.Event): Event set when the target is about to stop.
|
|
51
51
|
stopped_event (trio.Event): Event set when the target handling has fully stopped.
|
|
52
52
|
background_task_ended (Optional[trio.Event]): Event set when the background task completes.
|
|
53
|
-
_is_main_target (bool): Whether this is the primary target.
|
|
54
|
-
_logger_settings ("LoggerSettings"): Configuration for logging.
|
|
55
|
-
_domains_settings (Optional["DomainsSettings"]): Configuration for enabled domains and handlers.
|
|
56
|
-
_new_targets_filter_list (Sequence[Mapping[str, Any]]): Filters for discovering new targets.
|
|
57
|
-
_new_targets_buffer_size (int): Buffer size for new target events.
|
|
58
|
-
_nursery_object (trio.Nursery): Trio nursery for background tasks.
|
|
59
|
-
_target_background_task (Optional[devtools_background_func_type]): Optional background task to run.
|
|
60
|
-
_add_target_func (Callable): Callback to add a new target.
|
|
61
|
-
_remove_target_func (Callable): Callback to remove this target.
|
|
62
|
-
_add_cdp_log_func (Callable): Callback to record a CDP log entry.
|
|
63
|
-
_add_fingerprint_log_func (Callable): Callback to record a fingerprint log entry.
|
|
64
|
-
_fingerprint_injection_script (Optional[str]): JS script to inject into the target.
|
|
65
|
-
_new_targets_events_filters (Any): Validated filters for target events.
|
|
66
|
-
_cdp_target_type_log_accepted (bool): Whether CDP logging is enabled for this target type.
|
|
67
|
-
_cdp_log_stats (CDPLoggerChannelStats): Statistics for CDP logs.
|
|
68
|
-
_fingerprint_log_stats (FingerprintLoggerChannelStats): Statistics for fingerprint logs.
|
|
69
|
-
_logger_cdp_send_channel (Optional[trio.MemorySendChannel]): Channel to send CDP logs to the logger.
|
|
70
|
-
_logger_fingerprint_send_channel (Optional[trio.MemorySendChannel]): Channel to send fingerprint logs.
|
|
71
|
-
_logger (Optional[TargetLogger]): The logger instance for this target.
|
|
72
|
-
_cdp_session (Optional[CdpSession]): The active CDP session.
|
|
73
|
-
_new_target_receive_channel (Optional[Tuple[trio.MemoryReceiveChannel, trio.Event]]): Channel for new target events.
|
|
74
|
-
_detached_receive_channel (Optional[trio.MemoryReceiveChannel]): Channel for detach events.
|
|
75
|
-
_events_receive_channels (Dict[str, Tuple[trio.MemoryReceiveChannel, trio.Event]]): Channels for domain events.
|
|
76
53
|
"""
|
|
77
54
|
|
|
78
55
|
def __init__(
|
|
@@ -164,6 +141,7 @@ class BaseMixin:
|
|
|
164
141
|
self._new_target_receive_channel: Optional[Tuple[trio.MemoryReceiveChannel, trio.Event]] = None
|
|
165
142
|
self._detached_receive_channel: Optional[trio.MemoryReceiveChannel] = None
|
|
166
143
|
self._events_receive_channels: Dict[str, Tuple[trio.MemoryReceiveChannel, trio.Event]] = {}
|
|
144
|
+
self._cancel_scopes: Dict[str, trio.CancelScope] = {}
|
|
167
145
|
|
|
168
146
|
@property
|
|
169
147
|
def type_(self) -> Optional[str]:
|
|
@@ -258,6 +236,17 @@ class BaseMixin:
|
|
|
258
236
|
|
|
259
237
|
self.target_data.can_access_opener = value
|
|
260
238
|
|
|
239
|
+
@property
|
|
240
|
+
def cancel_scopes(self) -> Dict[str, trio.CancelScope]:
|
|
241
|
+
"""
|
|
242
|
+
Provides access to the dictionary of cancellation scopes.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Dict[str, trio.CancelScope]: The cancel scopes dictionary.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
return self._cancel_scopes
|
|
249
|
+
|
|
261
250
|
@property
|
|
262
251
|
def cdp_log_stats(self) -> CDPLoggerChannelStats:
|
|
263
252
|
"""
|
|
@@ -53,12 +53,17 @@ class LifecycleMixin(DiscoveryMixin, EventHandlersMixin, DetachMixin, Fingerprin
|
|
|
53
53
|
await self._logger.close()
|
|
54
54
|
self._logger = None
|
|
55
55
|
|
|
56
|
-
for channel in self._events_receive_channels.
|
|
56
|
+
for event_name, channel in self._events_receive_channels.items():
|
|
57
57
|
await channel[0].aclose()
|
|
58
58
|
await channel[1].wait()
|
|
59
59
|
|
|
60
60
|
self._events_receive_channels = {}
|
|
61
61
|
|
|
62
|
+
for scope_name, scope in self._cancel_scopes.items():
|
|
63
|
+
scope.cancel()
|
|
64
|
+
|
|
65
|
+
self._cancel_scopes = {}
|
|
66
|
+
|
|
62
67
|
if self.background_task_ended is not None:
|
|
63
68
|
await self.background_task_ended.wait()
|
|
64
69
|
self.background_task_ended = None
|
|
@@ -64,7 +64,11 @@ class LoggingMixin(BaseMixin):
|
|
|
64
64
|
await self._logger.run()
|
|
65
65
|
|
|
66
66
|
try:
|
|
67
|
-
self.
|
|
67
|
+
if self._logger.filter_cdp_log(log_entry=log_entry):
|
|
68
|
+
if self._logger_settings.cdp_settings.send_wait:
|
|
69
|
+
await self._logger_cdp_send_channel.send(log_entry)
|
|
70
|
+
else:
|
|
71
|
+
self._logger_cdp_send_channel.send_nowait(log_entry)
|
|
68
72
|
except trio.WouldBlock:
|
|
69
73
|
warnings.warn(
|
|
70
74
|
f"WARNING: Log channel for session {self.target_id} is full. Log dropped:\n{log_entry.model_dump_json(indent=4)}"
|
|
@@ -144,7 +148,11 @@ class LoggingMixin(BaseMixin):
|
|
|
144
148
|
await self._logger.run()
|
|
145
149
|
|
|
146
150
|
try:
|
|
147
|
-
self.
|
|
151
|
+
if self._logger.filter_fingerprint_log(log_entry=log_entry):
|
|
152
|
+
if self._logger_settings.fingerprint_settings.send_wait:
|
|
153
|
+
await self._logger_fingerprint_send_channel.send(log_entry)
|
|
154
|
+
else:
|
|
155
|
+
self._logger_fingerprint_send_channel.send_nowait(log_entry)
|
|
148
156
|
except trio.WouldBlock:
|
|
149
157
|
warnings.warn(
|
|
150
158
|
f"WARNING: Log channel for session {self.target_id} is full. Log dropped:\n{log_entry.model_dump_json(indent=4)}"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from osn_selenium._cdp_import import (
|
|
3
|
+
check_cdp_version_exists_on_github
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__all__ = ["CDPPackageError", "DependencyError"]
|
|
8
|
+
|
|
9
|
+
_CDP_PACKAGE_EXISTS = """
|
|
10
|
+
CDP package for {version} is not installed.
|
|
11
|
+
Fix: Run the following command:
|
|
12
|
+
\t`pip install git+https://github.com/oddshellnick/osn-selenium-cdp.git@{version}`
|
|
13
|
+
""".strip("\n")
|
|
14
|
+
|
|
15
|
+
_CDP_PACKAGE_NOT_EXISTS = """
|
|
16
|
+
CDP package for version {version} was not found on GitHub or locally.
|
|
17
|
+
Please check available versions at: https://github.com/oddshellnick/osn-selenium-cdp
|
|
18
|
+
If you need this specific version, you can generate it using the https://github.com/oddshellnick/selenium-package-parser tool.
|
|
19
|
+
""".strip("\n")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DependencyError(Exception):
|
|
23
|
+
"""
|
|
24
|
+
Base exception for dependency-related issues.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CDPPackageError(DependencyError):
|
|
31
|
+
"""
|
|
32
|
+
Exception raised when a required CDP package is missing.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, version: Union[int, str]):
|
|
36
|
+
"""
|
|
37
|
+
Initializes the error with version details.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
version (Union[int, str]): The missing CDP version.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
self.version = version if isinstance(version, str) else f"v{version}"
|
|
44
|
+
|
|
45
|
+
super().__init__(self._generate_report())
|
|
46
|
+
|
|
47
|
+
def _generate_report(self) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Generates a detailed error message checking remote availability.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
str: Formatted error message with instructions.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
version_exists_on_github = check_cdp_version_exists_on_github(version=self.version)
|
|
56
|
+
|
|
57
|
+
if version_exists_on_github:
|
|
58
|
+
return _CDP_PACKAGE_EXISTS.format(version=self.version)
|
|
59
|
+
|
|
60
|
+
return _CDP_PACKAGE_NOT_EXISTS.format(version=self.version)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Dict, Callable
|
|
3
|
+
|
|
4
|
+
from osn_selenium.abstract.executors.cdp import AbstractCDPExecutor
|
|
5
|
+
from osn_selenium.exceptions.dependencies import CDPPackageError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__all__ = ["CDPExecutor"]
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from osn_selenium_cdp_v140.executors.sync import CDP140Executor
|
|
12
|
+
from osn_selenium_cdp_v141.executors.sync import CDP141Executor
|
|
13
|
+
from osn_selenium_cdp_v142.executors.sync import CDP142Executor
|
|
14
|
+
from osn_selenium_cdp_v143.executors.sync import CDP143Executor
|
|
15
|
+
from osn_selenium_cdp_v144.executors.sync import CDP144Executor
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CDPExecutor(AbstractCDPExecutor):
|
|
19
|
+
"""
|
|
20
|
+
Global CDP executor router.
|
|
21
|
+
Handles lazy loading and version-specific package validation.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, execute_function: Callable[[str, Dict[str, Any]], Any]):
|
|
25
|
+
self._execute_function = execute_function
|
|
26
|
+
self._v140 = None
|
|
27
|
+
self._v141 = None
|
|
28
|
+
self._v142 = None
|
|
29
|
+
self._v143 = None
|
|
30
|
+
self._v144 = None
|
|
31
|
+
|
|
32
|
+
def get(self, version: int) -> Any:
|
|
33
|
+
"""
|
|
34
|
+
Dynamically loads and returns the CDP executor for a specific version.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
version (int): The CDP version number.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Any: The version-specific executor instance.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
CDPPackageError: If the version-specific package is not installed.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
if getattr(self, f"_v{version}", None) is None:
|
|
48
|
+
module = importlib.import_module(f"osn_selenium_cdp_v{version}.executors.sync")
|
|
49
|
+
executor_type = getattr(module, f"CDP{version}Executor")
|
|
50
|
+
|
|
51
|
+
setattr(self, f"_v{version}", executor_type(execute_function=self._execute_function))
|
|
52
|
+
|
|
53
|
+
return getattr(self, f"_v{version}", None)
|
|
54
|
+
except ImportError:
|
|
55
|
+
raise CDPPackageError(version=version)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def v140(self) -> "CDP140Executor":
|
|
59
|
+
"""
|
|
60
|
+
Get or initialize the executor for CDP version 140.
|
|
61
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
return self.get(version=140)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def v141(self) -> "CDP141Executor":
|
|
68
|
+
"""
|
|
69
|
+
Get or initialize the executor for CDP version 141.
|
|
70
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
return self.get(version=141)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def v142(self) -> "CDP142Executor":
|
|
77
|
+
"""
|
|
78
|
+
Get or initialize the executor for CDP version 142.
|
|
79
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
return self.get(version=142)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def v143(self) -> "CDP143Executor":
|
|
86
|
+
"""
|
|
87
|
+
Get or initialize the executor for CDP version 143.
|
|
88
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
return self.get(version=143)
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def v144(self) -> "CDP144Executor":
|
|
95
|
+
"""
|
|
96
|
+
Get or initialize the executor for CDP version 144.
|
|
97
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
return self.get(version=144)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Dict, Callable
|
|
3
|
+
|
|
4
|
+
import trio
|
|
5
|
+
|
|
6
|
+
from osn_selenium.abstract.executors.cdp import AbstractCDPExecutor
|
|
7
|
+
from osn_selenium.exceptions.dependencies import CDPPackageError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = ["CDPExecutor"]
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from osn_selenium_cdp_v140.executors.trio_threads import CDP140Executor
|
|
14
|
+
from osn_selenium_cdp_v141.executors.trio_threads import CDP141Executor
|
|
15
|
+
from osn_selenium_cdp_v142.executors.trio_threads import CDP142Executor
|
|
16
|
+
from osn_selenium_cdp_v143.executors.trio_threads import CDP143Executor
|
|
17
|
+
from osn_selenium_cdp_v144.executors.trio_threads import CDP144Executor
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CDPExecutor(AbstractCDPExecutor):
|
|
21
|
+
"""
|
|
22
|
+
Global CDP executor router.
|
|
23
|
+
Handles lazy loading and version-specific package validation.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, execute_function: Callable[[str, Dict[str, Any]], Any], lock: trio.Lock, limiter: trio.CapacityLimiter):
|
|
27
|
+
self._execute_function = execute_function
|
|
28
|
+
self._lock = lock
|
|
29
|
+
self._limiter = limiter
|
|
30
|
+
self._v140 = None
|
|
31
|
+
self._v141 = None
|
|
32
|
+
self._v142 = None
|
|
33
|
+
self._v143 = None
|
|
34
|
+
self._v144 = None
|
|
35
|
+
|
|
36
|
+
def get(self, version: int) -> Any:
|
|
37
|
+
"""
|
|
38
|
+
Dynamically loads and returns the CDP executor for a specific version.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
version (int): The CDP version number.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Any: The version-specific executor instance.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
CDPPackageError: If the version-specific package is not installed.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
if getattr(self, f"_v{version}", None) is None:
|
|
52
|
+
module = importlib.import_module(f"osn_selenium_cdp_v{version}.executors.trio_threads")
|
|
53
|
+
executor_type = getattr(module, f"CDP{version}Executor")
|
|
54
|
+
|
|
55
|
+
setattr(self, f"_v{version}", executor_type(execute_function=self._execute_function, lock=self._lock, limiter=self._limiter))
|
|
56
|
+
|
|
57
|
+
return getattr(self, f"_v{version}", None)
|
|
58
|
+
except ImportError:
|
|
59
|
+
raise CDPPackageError(version=version)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def v140(self) -> "CDP140Executor":
|
|
63
|
+
"""
|
|
64
|
+
Get or initialize the executor for CDP version 140.
|
|
65
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
return self.get(version=140)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def v141(self) -> "CDP141Executor":
|
|
72
|
+
"""
|
|
73
|
+
Get or initialize the executor for CDP version 141.
|
|
74
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
return self.get(version=141)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def v142(self) -> "CDP142Executor":
|
|
81
|
+
"""
|
|
82
|
+
Get or initialize the executor for CDP version 142.
|
|
83
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
return self.get(version=142)
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def v143(self) -> "CDP143Executor":
|
|
90
|
+
"""
|
|
91
|
+
Get or initialize the executor for CDP version 143.
|
|
92
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
return self.get(version=143)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def v144(self) -> "CDP144Executor":
|
|
99
|
+
"""
|
|
100
|
+
Get or initialize the executor for CDP version 144.
|
|
101
|
+
Raises CDPPackageError if the version-specific package is not installed.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
return self.get(version=144)
|
|
@@ -21,10 +21,6 @@ __all__ = ["UnifiedJSExecutor"]
|
|
|
21
21
|
class UnifiedJSExecutor:
|
|
22
22
|
"""
|
|
23
23
|
A unified executor for JavaScript scripts within the Selenium environment.
|
|
24
|
-
|
|
25
|
-
Attributes:
|
|
26
|
-
_execute_function (Callable[[str, Any], Any]): The internal function used to execute JS code.
|
|
27
|
-
_scripts (JS_Scripts): A collection of pre-defined JavaScript scripts.
|
|
28
24
|
"""
|
|
29
25
|
|
|
30
26
|
def __init__(self, execute_function: Callable[[str, Any], Any]):
|
osn_selenium/flags/base.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
|
-
from osn_selenium.
|
|
2
|
+
from osn_selenium._base_models import DictModel
|
|
3
3
|
from typing import (
|
|
4
4
|
Any,
|
|
5
5
|
Dict,
|
|
@@ -47,14 +47,6 @@ class BrowserFlagsManager:
|
|
|
47
47
|
|
|
48
48
|
This class provides a structured way to define, set, and build browser options
|
|
49
49
|
for various Selenium WebDriver instances.
|
|
50
|
-
|
|
51
|
-
Attributes:
|
|
52
|
-
_flags_types (Dict[str, FlagType]): A dictionary mapping flag types to their handler functions.
|
|
53
|
-
_flags_definitions (Dict[str, FlagDefinition]): A dictionary of all available flag definitions.
|
|
54
|
-
_flags_definitions_by_types (Dict[str, Dict[str, FlagDefinition]]): Flags definitions grouped by type.
|
|
55
|
-
_arguments (Dict[str, ArgumentValue]): Stores the configured command-line arguments.
|
|
56
|
-
_experimental_options (Dict[str, ExperimentalOptionValue]): Stores the configured experimental options.
|
|
57
|
-
_attributes (Dict[str, AttributeValue]): Stores the configured WebDriver attributes.
|
|
58
50
|
"""
|
|
59
51
|
|
|
60
52
|
def __init__(
|
osn_selenium/flags/blink.py
CHANGED
|
@@ -44,12 +44,6 @@ class BlinkFlagsManager(BrowserFlagsManager):
|
|
|
44
44
|
This class extends `BrowserFlagsManager` to handle Blink-specific features,
|
|
45
45
|
such as `--enable-blink-features` and `--disable-blink-features`, and provides
|
|
46
46
|
a comprehensive set of predefined flags for these browsers.
|
|
47
|
-
|
|
48
|
-
Attributes:
|
|
49
|
-
_browser_exe (Optional[PATH_TYPEHINT]): Path to the browser executable.
|
|
50
|
-
_start_page_url (Optional[str]): The URL to open when the browser starts.
|
|
51
|
-
_enable_blink_features (Dict[str, str]): Stores enabled Blink feature commands.
|
|
52
|
-
_disable_blink_features (Dict[str, str]): Stores disabled Blink feature commands.
|
|
53
47
|
"""
|
|
54
48
|
|
|
55
49
|
def __init__(
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
from pydantic import Field
|
|
2
|
-
from osn_selenium.models import (
|
|
3
|
-
DictModel,
|
|
4
|
-
ExtraDictModel
|
|
5
|
-
)
|
|
6
2
|
from typing import (
|
|
7
3
|
Any,
|
|
8
4
|
Callable,
|
|
@@ -10,6 +6,10 @@ from typing import (
|
|
|
10
6
|
Literal,
|
|
11
7
|
Optional
|
|
12
8
|
)
|
|
9
|
+
from osn_selenium._base_models import (
|
|
10
|
+
DictModel,
|
|
11
|
+
ExtraDictModel
|
|
12
|
+
)
|
|
13
13
|
from osn_selenium.flags._typehints import (
|
|
14
14
|
ANY_WEBDRIVER_OPTION_TYPEHINT
|
|
15
15
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pydantic import Field
|
|
2
2
|
from typing import Optional
|
|
3
|
-
from osn_selenium.models import ExtraDictModel
|
|
4
3
|
from osn_selenium._typehints import PATH_TYPEHINT
|
|
4
|
+
from osn_selenium._base_models import ExtraDictModel
|
|
5
5
|
from osn_selenium.flags._typehints import (
|
|
6
6
|
AUTOPLAY_POLICY_TYPEHINT,
|
|
7
7
|
LOG_LEVEL_TYPEHINT,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from osn_selenium.instances.sync.action_chains.move import MoveMixin
|
|
1
2
|
from osn_selenium.instances.sync.action_chains.click import ClickMixin
|
|
2
3
|
from osn_selenium.instances.sync.action_chains.utils import UtilsMixin
|
|
4
|
+
from osn_selenium.instances.sync.action_chains.scroll import ScrollMixin
|
|
3
5
|
from osn_selenium.instances.sync.action_chains.hm_move import HMMoveMixin
|
|
6
|
+
from osn_selenium.instances.sync.action_chains.keyboard import KeyboardMixin
|
|
4
7
|
from osn_selenium.instances.sync.action_chains.hm_scroll import HMScrollMixin
|
|
5
8
|
from osn_selenium.abstract.instances.action_chains import AbstractActionChains
|
|
6
9
|
from osn_selenium.instances.sync.action_chains.hm_keyboard import HMKeyboardMixin
|
|
@@ -17,6 +20,9 @@ class ActionChains(
|
|
|
17
20
|
HMKeyboardMixin,
|
|
18
21
|
HMMoveMixin,
|
|
19
22
|
HMScrollMixin,
|
|
23
|
+
KeyboardMixin,
|
|
24
|
+
MoveMixin,
|
|
25
|
+
ScrollMixin,
|
|
20
26
|
AbstractActionChains,
|
|
21
27
|
):
|
|
22
28
|
"""
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from selenium.webdriver.common.by import By
|
|
2
|
+
from osn_selenium.instances._typehints import SHADOW_ROOT_TYPEHINT
|
|
2
3
|
from typing import (
|
|
3
4
|
List,
|
|
4
5
|
Optional,
|
|
5
6
|
Self,
|
|
6
|
-
TYPE_CHECKING
|
|
7
|
+
TYPE_CHECKING,
|
|
8
|
+
Type
|
|
7
9
|
)
|
|
8
|
-
from osn_selenium.instances._typehints import SHADOW_ROOT_TYPEHINT
|
|
9
10
|
from osn_selenium.exceptions.instance import (
|
|
10
11
|
CannotConvertTypeError
|
|
11
12
|
)
|
|
@@ -14,6 +15,9 @@ from osn_selenium.abstract.instances.shadow_root import AbstractShadowRoot
|
|
|
14
15
|
from selenium.webdriver.remote.shadowroot import (
|
|
15
16
|
ShadowRoot as legacyShadowRoot
|
|
16
17
|
)
|
|
18
|
+
from selenium.webdriver.remote.webelement import (
|
|
19
|
+
WebElement as legacyWebElement
|
|
20
|
+
)
|
|
17
21
|
from osn_selenium.instances.convert import (
|
|
18
22
|
get_legacy_instance,
|
|
19
23
|
get_sync_instance_wrapper
|
|
@@ -25,6 +29,28 @@ __all__ = ["ShadowRoot"]
|
|
|
25
29
|
if TYPE_CHECKING:
|
|
26
30
|
from osn_selenium.instances.sync.web_element import WebElement
|
|
27
31
|
|
|
32
|
+
_WEB_ELEMENT_TYPE: Optional[Type["WebElement"]] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _build_web_element(legacy_element: legacyWebElement):
|
|
36
|
+
"""
|
|
37
|
+
Builds a wrapped WebElement from a legacy element.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
legacy_element (legacyWebElement): The legacy Selenium WebElement instance.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
WebElement: The wrapped WebElement instance.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
global _WEB_ELEMENT_TYPE
|
|
47
|
+
|
|
48
|
+
if _WEB_ELEMENT_TYPE is None:
|
|
49
|
+
from osn_selenium.instances.sync.web_element import WebElement
|
|
50
|
+
_WEB_ELEMENT_TYPE = WebElement
|
|
51
|
+
|
|
52
|
+
return get_sync_instance_wrapper(wrapper_class=_WEB_ELEMENT_TYPE, legacy_object=legacy_element)
|
|
53
|
+
|
|
28
54
|
|
|
29
55
|
class ShadowRoot(UnifiedShadowRoot, AbstractShadowRoot):
|
|
30
56
|
"""
|
|
@@ -47,17 +73,13 @@ class ShadowRoot(UnifiedShadowRoot, AbstractShadowRoot):
|
|
|
47
73
|
def find_element(self, by: str = By.ID, value: Optional[str] = None) -> "WebElement":
|
|
48
74
|
legacy_element = self._find_element_impl(by=by, value=value)
|
|
49
75
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return get_sync_instance_wrapper(wrapper_class=WebElement, legacy_object=legacy_element)
|
|
76
|
+
return _build_web_element(legacy_element=legacy_element)
|
|
53
77
|
|
|
54
78
|
def find_elements(self, by: str = By.ID, value: Optional[str] = None) -> List["WebElement"]:
|
|
55
79
|
legacy_elements = self._find_elements_impl(by=by, value=value)
|
|
56
80
|
|
|
57
|
-
from osn_selenium.instances.sync.web_element import WebElement
|
|
58
|
-
|
|
59
81
|
return [
|
|
60
|
-
|
|
82
|
+
_build_web_element(legacy_element=legacy_element)
|
|
61
83
|
for legacy_element in legacy_elements
|
|
62
84
|
]
|
|
63
85
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
from osn_selenium.instances.trio_threads.action_chains.move import MoveMixin
|
|
1
2
|
from osn_selenium.abstract.instances.action_chains import AbstractActionChains
|
|
2
3
|
from osn_selenium.instances.trio_threads.action_chains.click import ClickMixin
|
|
3
4
|
from osn_selenium.instances.trio_threads.action_chains.utils import UtilsMixin
|
|
5
|
+
from osn_selenium.instances.trio_threads.action_chains.scroll import ScrollMixin
|
|
4
6
|
from osn_selenium.instances.trio_threads.action_chains.hm_move import HMMoveMixin
|
|
7
|
+
from osn_selenium.instances.trio_threads.action_chains.keyboard import KeyboardMixin
|
|
5
8
|
from osn_selenium.instances.trio_threads.action_chains.hm_scroll import HMScrollMixin
|
|
6
9
|
from osn_selenium.instances.trio_threads.action_chains.hm_keyboard import HMKeyboardMixin
|
|
7
10
|
from osn_selenium.instances.trio_threads.action_chains.drag_and_drop import DragAndDropMixin
|
|
@@ -17,6 +20,9 @@ class ActionChains(
|
|
|
17
20
|
HMKeyboardMixin,
|
|
18
21
|
HMMoveMixin,
|
|
19
22
|
HMScrollMixin,
|
|
23
|
+
KeyboardMixin,
|
|
24
|
+
MoveMixin,
|
|
25
|
+
ScrollMixin,
|
|
20
26
|
AbstractActionChains,
|
|
21
27
|
):
|
|
22
28
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import trio
|
|
2
2
|
from typing import Optional, Self
|
|
3
|
-
from osn_selenium.
|
|
3
|
+
from osn_selenium.trio_threads_mixin import TrioThreadMixin
|
|
4
4
|
from osn_selenium.instances._typehints import ALERT_TYPEHINT
|
|
5
5
|
from osn_selenium.instances.unified.alert import UnifiedAlert
|
|
6
6
|
from osn_selenium.instances.convert import get_legacy_instance
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import trio
|
|
2
2
|
from typing import List, Self
|
|
3
|
-
from osn_selenium.
|
|
3
|
+
from osn_selenium.trio_threads_mixin import TrioThreadMixin
|
|
4
4
|
from osn_selenium.instances._typehints import BROWSER_TYPEHINT
|
|
5
5
|
from osn_selenium.instances.convert import get_legacy_instance
|
|
6
6
|
from osn_selenium.instances.unified.browser import UnifiedBrowser
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import trio
|
|
2
2
|
from typing import List, Optional, Self
|
|
3
|
-
from osn_selenium.
|
|
3
|
+
from osn_selenium.trio_threads_mixin import TrioThreadMixin
|
|
4
4
|
from selenium.webdriver.common.fedcm.account import Account
|
|
5
5
|
from osn_selenium.instances._typehints import DIALOG_TYPEHINT
|
|
6
6
|
from osn_selenium.instances.convert import get_legacy_instance
|