mops 3.5.2__tar.gz → 3.5.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.
- {mops-3.5.2 → mops-3.5.3}/PKG-INFO +2 -2
- {mops-3.5.2 → mops-3.5.3}/README.md +1 -1
- {mops-3.5.2 → mops-3.5.3}/mops/__init__.py +1 -1
- {mops-3.5.2 → mops-3.5.3}/mops/base/driver_wrapper.py +25 -3
- {mops-3.5.2 → mops-3.5.3}/mops/base/element.py +2 -2
- {mops-3.5.2 → mops-3.5.3}/mops/base/page.py +1 -1
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/internal_mixin.py +41 -13
- {mops-3.5.2 → mops-3.5.3}/mops.egg-info/PKG-INFO +2 -2
- {mops-3.5.2 → mops-3.5.3}/mops/abstraction/driver_wrapper_abc.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/abstraction/element_abc.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/abstraction/mixin_abc.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/abstraction/page_abc.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/base/group.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/exceptions.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/js_scripts.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/keyboard_keys.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/capabilities.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/driver_mixin.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/native_context.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/box.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/driver.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/location.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/locator.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/locator_type.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/scrolls.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/size.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/visual_comaprison_mixin.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/mixins/objects/wait_result.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/playwright/play_driver.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/playwright/play_element.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/playwright/play_page.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/core/core_driver.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/core/core_element.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/core/core_page.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/driver/mobile_driver.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/driver/web_driver.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/elements/mobile_element.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/elements/web_element.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/pages/mobile_page.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/pages/web_page.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/selenium/sel_utils.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/shared_utils.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/utils/decorators.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/utils/internal_utils.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/utils/logs.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/utils/previous_object_driver.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/utils/selector_synchronizer.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops/visual_comparison.py +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops.egg-info/SOURCES.txt +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops.egg-info/dependency_links.txt +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops.egg-info/requires.txt +0 -0
- {mops-3.5.2 → mops-3.5.3}/mops.egg-info/top_level.txt +0 -0
- {mops-3.5.2 → mops-3.5.3}/pyproject.toml +0 -0
- {mops-3.5.2 → mops-3.5.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mops
|
|
3
|
-
Version: 3.5.
|
|
3
|
+
Version: 3.5.3
|
|
4
4
|
Summary: Wrapper of Selenium, Appium and Playwright with single API
|
|
5
5
|
Author-email: Podolian Vladimir <vladimir.podolyan64@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Requires-Dist: Pillow>=12.1.0
|
|
|
44
44
|
</p>
|
|
45
45
|
|
|
46
46
|
<p align="center">
|
|
47
|
-
<a href="https://mops.readthedocs.io"><img alt="Documentation Status" src="https://
|
|
47
|
+
<a href="https://mops.readthedocs.io"><img alt="Documentation Status" src="https://readthedocs.org/projects/mops/badge/?version=latest"></a>
|
|
48
48
|
<a href="https://github.com/CustomEnv/mops/actions/workflows/static_tests.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/CustomEnv/mops/static_tests.yml?branch=master&logo=github&label=Unit%20Tests&labelColor=%232E353B"></a>
|
|
49
49
|
<a href="https://github.com/CustomEnv/mops/actions/workflows/playwright_tests.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/CustomEnv/mops/playwright_tests.yml?branch=master&logo=github&label=Playwright%20Tests&labelColor=%232E353B"></a>
|
|
50
50
|
</p>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
|
-
<a href="https://mops.readthedocs.io"><img alt="Documentation Status" src="https://
|
|
14
|
+
<a href="https://mops.readthedocs.io"><img alt="Documentation Status" src="https://readthedocs.org/projects/mops/badge/?version=latest"></a>
|
|
15
15
|
<a href="https://github.com/CustomEnv/mops/actions/workflows/static_tests.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/CustomEnv/mops/static_tests.yml?branch=master&logo=github&label=Unit%20Tests&labelColor=%232E353B"></a>
|
|
16
16
|
<a href="https://github.com/CustomEnv/mops/actions/workflows/playwright_tests.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/CustomEnv/mops/playwright_tests.yml?branch=master&logo=github&label=Playwright%20Tests&labelColor=%232E353B"></a>
|
|
17
17
|
</p>
|
|
@@ -15,8 +15,6 @@ from mops.abstraction.driver_wrapper_abc import DriverWrapperABC
|
|
|
15
15
|
from mops.exceptions import DriverWrapperException
|
|
16
16
|
from mops.js_scripts import storage_get_items_js, storage_set_item_js
|
|
17
17
|
from mops.mixins.internal_mixin import InternalMixin
|
|
18
|
-
from mops.mixins.objects.box import Box
|
|
19
|
-
from mops.mixins.objects.driver import Driver
|
|
20
18
|
from mops.mixins.objects.visual_comaprison_mixin import hide_before_screenshot, reveal_after_screenshot
|
|
21
19
|
from mops.playwright.play_driver import PlayDriver
|
|
22
20
|
from mops.selenium.driver.mobile_driver import MobileDriver
|
|
@@ -37,6 +35,7 @@ if TYPE_CHECKING:
|
|
|
37
35
|
|
|
38
36
|
class DriverWrapperSessions:
|
|
39
37
|
all_sessions: ClassVar[list[DriverWrapper]] = []
|
|
38
|
+
_MIN_SESSIONS_FOR_COMPARISON: ClassVar[int] = 2
|
|
40
39
|
|
|
41
40
|
@classmethod
|
|
42
41
|
def add_session(cls, driver_wrapper: DriverWrapper) -> None:
|
|
@@ -87,6 +86,29 @@ class DriverWrapperSessions:
|
|
|
87
86
|
"""
|
|
88
87
|
return any(cls.all_sessions)
|
|
89
88
|
|
|
89
|
+
@classmethod
|
|
90
|
+
def has_different_driver_types(cls) -> bool:
|
|
91
|
+
"""
|
|
92
|
+
Check if the session pool contains different driver types
|
|
93
|
+
(e.g., Selenium + Appium, Selenium + Playwright).
|
|
94
|
+
|
|
95
|
+
:return: :obj:`bool` - :obj:`True` if at least two sessions use different driver types,
|
|
96
|
+
otherwise :obj:`False`.
|
|
97
|
+
"""
|
|
98
|
+
if len(cls.all_sessions) < cls._MIN_SESSIONS_FOR_COMPARISON:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
driver_types = set()
|
|
102
|
+
for session in cls.all_sessions:
|
|
103
|
+
if session.is_playwright:
|
|
104
|
+
driver_types.add('playwright')
|
|
105
|
+
elif session.is_appium:
|
|
106
|
+
driver_types.add('appium')
|
|
107
|
+
elif session.is_selenium:
|
|
108
|
+
driver_types.add('selenium')
|
|
109
|
+
|
|
110
|
+
return len(driver_types) > 1
|
|
111
|
+
|
|
90
112
|
|
|
91
113
|
class DriverWrapper(InternalMixin, Logging, DriverWrapperABC):
|
|
92
114
|
"""
|
|
@@ -478,7 +500,7 @@ class DriverWrapper(InternalMixin, Logging, DriverWrapperABC):
|
|
|
478
500
|
)
|
|
479
501
|
raise DriverWrapperException(msg)
|
|
480
502
|
|
|
481
|
-
self._set_static(self._base_cls)
|
|
503
|
+
self._set_static(self._base_cls, with_shadow=False)
|
|
482
504
|
self._base_cls.__init__(self, driver_container=self.__driver_container)
|
|
483
505
|
|
|
484
506
|
for name, value in self.__dict__.items():
|
|
@@ -66,7 +66,7 @@ class ElementMeta(ABCMeta):
|
|
|
66
66
|
@functools.wraps(orig_init)
|
|
67
67
|
def wrapped_init(self: Any, *args: Any, **kw: Any) -> None:
|
|
68
68
|
orig_init(self, *args, **kw)
|
|
69
|
-
if
|
|
69
|
+
if getattr(self, '_initialized', False):
|
|
70
70
|
self._modify_sub_elements()
|
|
71
71
|
|
|
72
72
|
cls.__init__ = wrapped_init
|
|
@@ -181,7 +181,7 @@ class Element(DriverMixin, InternalMixin, Logging, ElementABC, metaclass=Element
|
|
|
181
181
|
)
|
|
182
182
|
raise DriverWrapperException(msg)
|
|
183
183
|
|
|
184
|
-
self._set_static(self._base_cls)
|
|
184
|
+
self._set_static(self._base_cls, with_shadow=True)
|
|
185
185
|
self._base_cls.__init__(self)
|
|
186
186
|
self._initialized = True
|
|
187
187
|
|
|
@@ -108,7 +108,7 @@ class Page(DriverMixin, InternalMixin, Logging, PageABC):
|
|
|
108
108
|
)
|
|
109
109
|
raise DriverWrapperException(msg)
|
|
110
110
|
|
|
111
|
-
self._set_static(self._base_cls)
|
|
111
|
+
self._set_static(self._base_cls, with_shadow=True)
|
|
112
112
|
self._base_cls.__init__(self)
|
|
113
113
|
|
|
114
114
|
@cached_property
|
|
@@ -6,9 +6,11 @@ from typing import Any
|
|
|
6
6
|
from mops.utils.internal_utils import (
|
|
7
7
|
extract_all_named_objects,
|
|
8
8
|
extract_named_objects,
|
|
9
|
-
is_driver_wrapper,
|
|
10
9
|
)
|
|
11
10
|
|
|
11
|
+
_shadow_classes: dict[tuple[type, str], type] = {}
|
|
12
|
+
_class_configured: dict[type, type] = {}
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
def get_element_info(element: Any, label: str = 'Selector=') -> str:
|
|
14
16
|
"""
|
|
@@ -47,6 +49,7 @@ def get_driver_instance(driver_type: type, instance: type) -> bool:
|
|
|
47
49
|
|
|
48
50
|
class InternalMixin:
|
|
49
51
|
driver: None
|
|
52
|
+
driver_wrapper: None
|
|
50
53
|
|
|
51
54
|
def _driver_is_instance(self, instance: type) -> bool:
|
|
52
55
|
"""Check if the current driver is an instance of the given type."""
|
|
@@ -56,33 +59,58 @@ class InternalMixin:
|
|
|
56
59
|
if not hasattr(self, var):
|
|
57
60
|
setattr(self, var, value)
|
|
58
61
|
|
|
59
|
-
def _get_protected_attrs(self: Any, current_obj_cls: type) ->
|
|
60
|
-
if not is_driver_wrapper(self):
|
|
61
|
-
return set(get_all_static_attributes(current_obj_cls))
|
|
62
|
-
|
|
62
|
+
def _get_protected_attrs(self: Any, current_obj_cls: type) -> frozenset:
|
|
63
63
|
if '_framework_attrs' not in current_obj_cls.__dict__:
|
|
64
|
-
current_obj_cls._framework_attrs =
|
|
64
|
+
current_obj_cls._framework_attrs = frozenset(get_all_static_attributes(current_obj_cls))
|
|
65
65
|
|
|
66
66
|
return current_obj_cls.__dict__['_framework_attrs']
|
|
67
67
|
|
|
68
|
-
def _set_static(self: Any, cls: type) -> None:
|
|
68
|
+
def _set_static(self: Any, cls: type, with_shadow: bool) -> None:
|
|
69
69
|
"""
|
|
70
|
-
Set
|
|
70
|
+
Set attributes from base cls onto the class. Uses per-driver shadow
|
|
71
|
+
classes when multiple driver types are active.
|
|
71
72
|
|
|
72
73
|
:return: None
|
|
73
74
|
"""
|
|
74
|
-
|
|
75
|
+
obj_cls = self.__class__
|
|
75
76
|
|
|
76
|
-
if
|
|
77
|
+
if _class_configured.get(obj_cls) is cls:
|
|
77
78
|
return
|
|
78
79
|
|
|
79
|
-
protected = self._get_protected_attrs(
|
|
80
|
+
protected = self._get_protected_attrs(obj_cls)
|
|
81
|
+
|
|
82
|
+
if with_shadow and self.driver_wrapper.session.has_different_driver_types():
|
|
83
|
+
obj_cls = self._set_shadow_class(protected)
|
|
80
84
|
|
|
81
85
|
for name, value in get_static_attributes(cls).items():
|
|
82
86
|
if name not in protected:
|
|
83
|
-
setattr(
|
|
87
|
+
setattr(obj_cls, name, value)
|
|
88
|
+
|
|
89
|
+
_class_configured[obj_cls] = cls
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
def _set_shadow_class(self, protected: frozenset) -> type:
|
|
92
|
+
"""
|
|
93
|
+
Create or reuse a per-driver shadow subclass. The given *protected*
|
|
94
|
+
set was computed from the original class before any attributes were
|
|
95
|
+
injected, so the shadow class starts with the same baseline.
|
|
96
|
+
|
|
97
|
+
:param protected: pre-computed _framework_attrs of the original class.
|
|
98
|
+
:return: the shadow class (a subtype of the original class).
|
|
99
|
+
"""
|
|
100
|
+
original_cls = self.__class__
|
|
101
|
+
key = (original_cls, self.driver_wrapper._base_cls.__name__)
|
|
102
|
+
obj_cls = _shadow_classes.get(key)
|
|
103
|
+
if not obj_cls:
|
|
104
|
+
obj_cls = type(
|
|
105
|
+
original_cls.__name__,
|
|
106
|
+
(original_cls,),
|
|
107
|
+
{'_shadow_class': True, '_framework_attrs': protected},
|
|
108
|
+
)
|
|
109
|
+
_shadow_classes[key] = obj_cls
|
|
110
|
+
|
|
111
|
+
self.__class__ = obj_cls
|
|
112
|
+
|
|
113
|
+
return obj_cls
|
|
86
114
|
|
|
87
115
|
def _repr_builder(self: Any) -> str | None:
|
|
88
116
|
class_name = self.__class__.__name__
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mops
|
|
3
|
-
Version: 3.5.
|
|
3
|
+
Version: 3.5.3
|
|
4
4
|
Summary: Wrapper of Selenium, Appium and Playwright with single API
|
|
5
5
|
Author-email: Podolian Vladimir <vladimir.podolyan64@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Requires-Dist: Pillow>=12.1.0
|
|
|
44
44
|
</p>
|
|
45
45
|
|
|
46
46
|
<p align="center">
|
|
47
|
-
<a href="https://mops.readthedocs.io"><img alt="Documentation Status" src="https://
|
|
47
|
+
<a href="https://mops.readthedocs.io"><img alt="Documentation Status" src="https://readthedocs.org/projects/mops/badge/?version=latest"></a>
|
|
48
48
|
<a href="https://github.com/CustomEnv/mops/actions/workflows/static_tests.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/CustomEnv/mops/static_tests.yml?branch=master&logo=github&label=Unit%20Tests&labelColor=%232E353B"></a>
|
|
49
49
|
<a href="https://github.com/CustomEnv/mops/actions/workflows/playwright_tests.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/CustomEnv/mops/playwright_tests.yml?branch=master&logo=github&label=Playwright%20Tests&labelColor=%232E353B"></a>
|
|
50
50
|
</p>
|
|
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
|