pomcorn 0.7.0__py3-none-any.whl → 0.7.1__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.

Potentially problematic release.


This version of pomcorn might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, NoReturn
3
+ from typing import TYPE_CHECKING, NoReturn, overload
4
4
 
5
5
  from pomcorn import locators
6
6
 
@@ -23,23 +23,39 @@ class Element:
23
23
 
24
24
  cache_attribute_name = "cached_elements"
25
25
 
26
+ @overload
26
27
  def __init__(
27
28
  self,
28
- locator: locators.XPathLocator,
29
- is_relative_locator: bool = True,
29
+ locator: locators.XPathLocator | None = None,
30
+ ) -> None:
31
+ ...
32
+
33
+ @overload
34
+ def __init__(
35
+ self,
36
+ *,
37
+ relative_locator: locators.XPathLocator | None = None,
38
+ ) -> None:
39
+ ...
40
+
41
+ def __init__(
42
+ self,
43
+ locator: locators.XPathLocator | None = None,
44
+ *,
45
+ relative_locator: locators.XPathLocator | None = None,
30
46
  ) -> None:
31
47
  """Initialize descriptor.
32
48
 
33
- Args:
34
- locator: Instance of a class to locate the element in
35
- the browser.
36
- is_relative_locator: Whether add parent ``base_locator`` to the
37
- current descriptors's `base_locator` or not. If descriptor is
38
- used for ``Page``, the value of this argument will not be used.
49
+ Use `relative_locator` if you need to include `base_locator` of
50
+ instance, otherwise use `locator`.
51
+
52
+ If descriptor is used for instance of ``Page``, then
53
+ ``relative_locator`` is not needed, since element will be searched
54
+ across the entire page, not within some component.
39
55
 
40
56
  """
41
- self.is_relative_locator = is_relative_locator
42
57
  self.locator = locator
58
+ self.relative_locator = relative_locator
43
59
 
44
60
  def __set_name__(self, _owner: type, name: str) -> None:
45
61
  """Save attribute name for which descriptor is created."""
@@ -69,10 +85,6 @@ class Element:
69
85
  ``self.is_relative_locator=True``, element will be found by sum of
70
86
  ``base_locator`` of that component and passed locator of descriptor.
71
87
 
72
- If descriptor is used for instance of ``Page``, then ``base_locator``
73
- is not needed, since element will be searched across the entire page,
74
- not within some component.
75
-
76
88
  """
77
89
  if not getattr(instance, self.cache_attribute_name, None):
78
90
  setattr(instance, self.cache_attribute_name, {})
@@ -81,15 +93,49 @@ class Element:
81
93
  if cached_element := cache.get(self.attribute_name):
82
94
  return cached_element
83
95
 
84
- from pomcorn import Component
85
-
86
- if self.is_relative_locator and isinstance(instance, Component):
87
- self.locator = instance.base_locator // self.locator
88
-
89
- element = instance.init_element(locator=self.locator)
96
+ element = instance.init_element(
97
+ locator=self._prepare_locator(instance),
98
+ )
90
99
  cache[self.attribute_name] = element
91
100
 
92
101
  return element
93
102
 
103
+ def _prepare_locator(self, instance: WebView) -> locators.XPathLocator:
104
+ """Prepare a locator by arguments.
105
+
106
+ Check that only one locator argument is passed, or none.
107
+ If only `relative_locator` was passed, `base_locator` of instance will
108
+ be added to specified in descriptor arguments. If only `locator` was
109
+ passed, it will return only specified one.
110
+
111
+ Raises:
112
+ ValueError: If both arguments were passed or neither or
113
+ ``relative_locator`` used not in ``Component``.
114
+
115
+ """
116
+ if self.relative_locator and self.locator:
117
+ raise ValueError(
118
+ "You need to pass only one of the arguments: "
119
+ "`locator` or `relative_locator`.",
120
+ )
121
+
122
+ if not self.relative_locator:
123
+ if not self.locator:
124
+ raise ValueError(
125
+ "You need to pass one of the arguments: "
126
+ "`locator` or `relative_locator`.",
127
+ )
128
+ return self.locator
129
+
130
+ from pomcorn import Component
131
+
132
+ if self.relative_locator and isinstance(instance, Component):
133
+ return instance.base_locator // self.relative_locator
134
+
135
+ raise ValueError(
136
+ f"`relative_locator` should be used only if descriptor used in "
137
+ f"component. `{instance}` is not a component.",
138
+ )
139
+
94
140
  def __set__(self, *args, **kwargs) -> NoReturn:
95
141
  raise ValueError("You can't reset an element attribute value!")
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Iterator
4
- from typing import TypeVar
4
+ from typing import Literal, TypeVar
5
5
 
6
6
  from selenium.webdriver.common.by import By
7
7
 
@@ -120,16 +120,22 @@ class XPathLocator(Locator):
120
120
  super().__init__(by=By.XPATH, query=query)
121
121
 
122
122
  def __truediv__(self, other: XPathLocator) -> XPathLocator:
123
- """Override `/` operator to implement following XPath locators."""
124
- return XPathLocator(
125
- query=f"//{self.related_query}/{other.related_query}",
126
- )
123
+ """Override `/` operator to implement following XPath locators.
124
+
125
+ "/" used to select the nearest children of the current node.
126
+
127
+ """
128
+ return self.prepare_relative_locator(other=other, separator="/")
127
129
 
128
130
  def __floordiv__(self, other: XPathLocator) -> XPathLocator:
129
- """Override `//` operator to implement nested XPath locators."""
130
- return XPathLocator(
131
- query=f"//{self.related_query}//{other.related_query}",
132
- )
131
+ """Override `//` operator to implement nested XPath locators.
132
+
133
+ "//" used to select all descendants (children, grandchildren,
134
+ great-grandchildren, etc.) of current node, regardless of their level
135
+ in hierarchy.
136
+
137
+ """
138
+ return self.prepare_relative_locator(other=other, separator="//")
133
139
 
134
140
  def __or__(self, other: XPathLocator) -> XPathLocator:
135
141
  r"""Override `|` operator to implement variant XPath locators.
@@ -146,6 +152,10 @@ class XPathLocator(Locator):
146
152
  """
147
153
  return XPathLocator(query=f"({self.query} | {other.query})")
148
154
 
155
+ def __bool__(self) -> bool:
156
+ """Return whether query of current locator is empty or not."""
157
+ return bool(self.related_query)
158
+
149
159
  def extend_query(self, extra_query: str) -> XPathLocator:
150
160
  """Return new XPathLocator with extended query."""
151
161
  return XPathLocator(query=self.query + extra_query)
@@ -165,3 +175,49 @@ class XPathLocator(Locator):
165
175
  partial_query = f"[contains(., '{text}')]"
166
176
  exact_query = f"[./text()='{text}']"
167
177
  return self.extend_query(exact_query if exact else partial_query)
178
+
179
+ def prepare_relative_locator(
180
+ self,
181
+ other: XPathLocator,
182
+ separator: Literal["/", "//"] = "/",
183
+ ) -> XPathLocator:
184
+ """Prepare relative locator base on queries of two locators.
185
+
186
+ If one of parent and other locator queries is empty, the method will
187
+ return only the filled one.
188
+
189
+ Args:
190
+ other: Child locator object.
191
+ separator: Literal which will placed between locators queries - "/"
192
+ used to select nearest children of current node and "//" used
193
+ to select all descendants (children, grandchildren,
194
+ great-grandchildren, etc.) of current node, regardless of their
195
+ level in hierarchy.
196
+
197
+ Raises:
198
+ ValueError: If parent and child locators queries are empty.
199
+
200
+ """
201
+ related_query = self.related_query
202
+ if not related_query.startswith("("):
203
+ # Parent query can be bracketed, in which case we don't need to use
204
+ # `//`
205
+ # Example:
206
+ # (//li)[3] -> valid
207
+ # //(//li)[3] -> invalid
208
+ related_query = f"//{self.related_query}"
209
+
210
+ locator = XPathLocator(
211
+ query=f"{related_query}{separator}{other.related_query}",
212
+ )
213
+
214
+ if self and other:
215
+ return locator
216
+
217
+ if not (self or other):
218
+ raise ValueError(
219
+ f"Both of locators have empty query. The `{locator.query}` is "
220
+ "not a valid locator.",
221
+ )
222
+
223
+ return other if not self else self
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pomcorn
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Base implementation of Page Object Model
5
5
  Home-page: https://pypi.org/project/pomcorn/
6
6
  License: MIT
@@ -1,17 +1,17 @@
1
1
  pomcorn/__init__.py,sha256=V8v_V3wgKbao1KAQkcVTMnpGwyslw0nHfuTp-DwWTXg,318
2
2
  pomcorn/component.py,sha256=7nRt-A20Psm0Xl7Rm6tRUK8yOhIh4t2Bdm1fwmJ0MjA,8385
3
3
  pomcorn/descriptors/__init__.py,sha256=5q_d5GtcaFlIIyHdsUnE9UNbz3g40qJCHKNaWGvcC6s,72
4
- pomcorn/descriptors/element.py,sha256=hde1dcKqKXH9DPKEHfaGyyYlDYlpOf4an-PulZQhxvI,3147
4
+ pomcorn/descriptors/element.py,sha256=4g_4ay5f00AXzCT4xHN1i7mTrlsECoUHh1Ph_TFPBDs,4502
5
5
  pomcorn/element.py,sha256=uxcqf3EK1TzDgdjQzhP2Ovf8GDsdas_tsJs_xPt62gI,12400
6
6
  pomcorn/exceptions.py,sha256=8ZOmrybDwvEVZRLQzyozjRNhJvSLbablaFwGFUVMhrU,1131
7
7
  pomcorn/locators/__init__.py,sha256=hNSlfmz3y-LI4PXF5VIwX8J5WSalyE2wmzuYc6kNxMA,708
8
- pomcorn/locators/base_locators.py,sha256=fk70jn87jOWx7eladEW7a9Vo4slYJnizW7yoLXijefU,5140
8
+ pomcorn/locators/base_locators.py,sha256=B4SDSKi5j7kqwbxllnMHU9BKBJzn_dzNRphPQ2hTuss,7065
9
9
  pomcorn/locators/xpath_locators.py,sha256=OjwTdHwqDfX_5aP0N6YeFwRl2gPr8ZNQny8yLxBrVCo,7264
10
10
  pomcorn/page.py,sha256=JdCDDVP4q2r5HwxSRnD9Sg43tgpCyrqu_jEux2E4ARY,5475
11
11
  pomcorn/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  pomcorn/waits_conditions.py,sha256=E8sLfBvIV2EO91Mm5KyKXB5IGEB9gUWza3XPE4_aCQE,3528
13
13
  pomcorn/web_view.py,sha256=PlwEVgdOwFZXJY2WuUT2C2wyK1xOBJne5-A_FOuwsQI,14209
14
- pomcorn-0.7.0.dist-info/LICENSE,sha256=1vmhQNp1dDH8ksJ199LuG4oKz5D4ZvNccPcFckiG2S4,1091
15
- pomcorn-0.7.0.dist-info/METADATA,sha256=jnkNjl4KfqhRHNr55CLycO3VWp-s0T-8Yh4ey29abGo,5949
16
- pomcorn-0.7.0.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
17
- pomcorn-0.7.0.dist-info/RECORD,,
14
+ pomcorn-0.7.1.dist-info/LICENSE,sha256=1vmhQNp1dDH8ksJ199LuG4oKz5D4ZvNccPcFckiG2S4,1091
15
+ pomcorn-0.7.1.dist-info/METADATA,sha256=plUXXe1KZnwCkzQm8M7XmRUMK0iSt1t11AW5LDfsMHo,5949
16
+ pomcorn-0.7.1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
17
+ pomcorn-0.7.1.dist-info/RECORD,,