Skip to content

Commit 066407b

Browse files
authored
update method to match selenium 4 find_element (#13)
1 parent 01eeae4 commit 066407b

File tree

14 files changed

+163
-71
lines changed

14 files changed

+163
-71
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,5 @@ venv.bak/
105105

106106
# mypy
107107
.mypy_cache/
108+
109+
demo.py

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ typing:
2020
check: lint typing
2121

2222
firefox:
23-
docker compose up -d selenium-firefox
23+
docker compose up -d --force-recreate selenium-firefox
2424

2525
testfirefox:
2626
pytest -v tests/ --driver Remote --capability browserName firefox --website http://website/ -x
2727

2828
chrome:
29-
docker compose up -d selenium-chrome
29+
docker compose up -d --force-recreate selenium-chrome
3030

3131
testchrome:
3232
pytest -v tests/ --driver Remote --capability browserName chrome --website http://website/ -x

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Niobium extends the Python Selenium client with nice features.
44

55
## Why Niobium
66

7-
Selenium is probably the better tool for web automation. But sometimes it's hard to write a clean automation script.
7+
Selenium is a good tool for web automation, but sometimes it's hard to write a clean automation script.
88

9-
With Niobium you can keep using Selenium and simplify your scripts. For example, Niobium adds a new element locator, find_element_by_image, which adds image recognition capacity in order to find an element in the webpage.
9+
With Niobium, you can keep using Selenium while simplifying your scripts. For example, Niobium adds a new element locator,` By.IMAGE`, which enables image recognition in `WebDriver.find_element` to locate an element on the webpage.
1010

1111
The goal of Niobium is not to replace Selenium. We only want to add to Selenium the functions we will love to see in Selenium natively.
1212

@@ -22,31 +22,37 @@ Niobium is available on Pypi, so simply use pip.
2222

2323
In order to use Niobium, you just need to import it in your script. Selenium will be automatically extended.
2424

25-
from selenium import webdriver
25+
```python
2626
import niobium
27+
from selenium import webdriver
2728

2829
driver = webdriver.Firefox()
2930
driver.implicitly_wait(10)
3031
driver.get("https://www.python.org/")
3132

32-
driver.find_element_by_image("logo_python.png")
33+
driver.find_element(By.IMAGE, "logo_python.png")
3334

3435
driver.quit()
36+
```
3537

3638
In order to avoid warning with your linter, you can import selenium from niobium.
3739

40+
```python
3841
from niobium import selenium
3942

4043
driver = selenium.webdriver.Firefox()
4144
...
45+
```
4246

4347
or simply disable the warning, like in this example for flake8
4448

45-
from selenium import webdriver
49+
```python
4650
import niobium # noqa: F401
51+
from selenium import webdriver
4752

4853
driver = webdriver.Firefox()
4954
...
55+
```
5056

5157
If you use pytest and especially pytest-selenium, just import niobium in your conftest.py.
5258

@@ -58,4 +64,4 @@ If you use pytest and especially pytest-selenium, just import niobium in your co
5864

5965
Some features implemented in Niobium are here only to help you when there is no other easy solution. If you do a bad usage of Niobium features, it can result to a bad performance in your script, or it will be difficult to maintain it. Please read the documentation in order to know the special warnings for the use of these features.
6066

61-
Niobium do not modify the Selenium library package. The patches are only applied at runtime.
67+
Niobium do not modify the Selenium library package. The patches are only applied at runtime. This is the reason why the autocompletion is not updated correctly.

docs/image.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,67 @@ Niobium adds computer vision to Selenium.
66

77
You can locate an image in the page using the following method:
88

9-
find_element_by_image(filename)
9+
```python
10+
find_element(By.IMAGE, filename)
11+
```
1012

1113
And to find multiple images (this method returns a list)
1214

13-
find_elements_by_image(filename)
15+
```python
16+
find_elements(By.IMAGE, filename)
17+
```
1418

15-
These methods have the same behavior than the classic find_element methods but they return an ImageElement instead of a WebElement.
19+
These methods have the same behavior than the classic `find_element` methods but they return an `ImageElement` instead of a `WebElement` if you use the `By.IMAGE` selector.
1620

1721
They take only one argument which is the path to the PNG image that you search.
1822

1923
## Find element by image
2024

21-
The methods find_element_by_image and find_elements_by_image are available only from the WebDriver object. Only the visible page is analyzed in order to locate the image.
25+
The methods `find_element` and `find_elements` using the selector `By.IMAGE` are available only from the `WebDriver` object. Only the visible page is analyzed in order to locate the image.
2226

27+
```python
2328
from selenium import webdriver
2429
import niobium # noqa: F401
2530

2631
driver = webdriver.Firefox()
2732
driver.implicitly_wait(10)
2833
driver.get("https://www.python.org/")
2934

30-
driver.find_element_by_image("logo_python.png")
35+
driver.find_element(By.IMAGE, "logo_python.png")
3136

3237
driver.quit()
38+
```
3339

3440
## Click on the image
3541

3642
You can click on the element.
3743

38-
driver.find_element_by_image("logo_python.png").click()
44+
```python
45+
driver.find_element(By.IMAGE, "logo_python.png").click()
46+
```
3947

4048
By default, the click is performed on the center of the element.
4149

4250
## Click with offset
4351

4452
You can click to a specific location related to the top left corner of the element with the `click_at(xoffset, yoffset)` function.
4553

46-
driver.find_element_by_image("logo_python.png").click_at(100, -100)
54+
```python
55+
driver.find_element(By.IMAGE, "logo_python.png").click_at(100, -100)
56+
```
4757

4858
## Move the cursor over the element
4959

5060
You can move the cursor to the center of the element with the `move_to()` function.
5161

52-
driver.find_element_by_image("logo_python.png").move_to()
62+
```python
63+
driver.find_element(By.IMAGE, "logo_python.png").move_to()
64+
```
5365

5466
## Move the cursor with offset
5567

5668
You can move the cursor to a specific location related to the top left corner of the element with the `move_at(xoffset, yoffset)` function.
5769

58-
driver.find_element_by_image("logo_python.png").move_at(20, 20)
59-
60-
70+
```python
71+
driver.find_element(By.IMAGE, "logo_python.png").move_at(20, 20)
72+
```

docs/index.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Niobium extends the Python Selenium client with nice features.
44

55
## Why Niobium
66

7-
Selenium is probably the better tool for web automation. But sometimes it's hard to write a clean automation script.
7+
Selenium is a good tool for web automation, but sometimes it's hard to write a clean automation script.
88

9-
With Niobium you can keep using Selenium and simplify your scripts. For example, Niobium adds a new element locator, find_element_by_image, which adds image recognition capacity in order to find an element in the webpage.
9+
With Niobium, you can keep using Selenium while simplifying your scripts. For example, Niobium adds a new element locator,` By.IMAGE`, which enables image recognition in `WebDriver.find_element` to locate an element on the webpage.
1010

1111
The goal of Niobium is not to replace Selenium. We only want to add to Selenium the functions we will love to see in Selenium natively.
1212

@@ -22,36 +22,42 @@ Niobium is available on Pypi, so simply use pip.
2222

2323
In order to use Niobium, you just need to import it in your script. Selenium will be automatically extended.
2424

25-
from selenium import webdriver
25+
```python
2626
import niobium
27+
from selenium import webdriver
2728

2829
driver = webdriver.Firefox()
2930
driver.implicitly_wait(10)
3031
driver.get("https://www.python.org/")
3132

32-
driver.find_element_by_image("logo_python.png")
33+
driver.find_element(By.IMAGE, "logo_python.png")
3334

3435
driver.quit()
36+
```
3537

3638
In order to avoid warning with your linter, you can import selenium from niobium.
3739

40+
```python
3841
from niobium import selenium
3942

4043
driver = selenium.webdriver.Firefox()
4144
...
45+
```
4246

4347
or simply disable the warning, like in this example for flake8
4448

45-
from selenium import webdriver
49+
```python
4650
import niobium # noqa: F401
51+
from selenium import webdriver
4752

4853
driver = webdriver.Firefox()
4954
...
55+
```
5056

5157
If you use *pytest* and especially *pytest-selenium*, just import niobium in your `conftest.py`.
5258

5359
## Warnings
5460

5561
Some features implemented in Niobium are here only to help you when there is no other easy solution. If you do a bad usage of Niobium features, it can result to a bad performance in your script, or it will be difficult to maintain it. Please read the documentation in order to know the special warnings for the use of these features.
5662

57-
Niobium do not modify the Selenium library package. The patches are only applied at runtime.
63+
Niobium do not modify the Selenium library package. The patches are only applied at runtime. This is the reason why the autocompletion is not updated correctly.

docs/webelement_action.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
# WebElement new actions
22

3-
Niobium make easier the mouse action on a WebElement.
3+
Niobium make easier the mouse action on a `WebElement`.
44

55
## Click with offset
66

77
You can click to a specific location related to the top left corner of the element with the `click_at(xoffset, yoffset)` function.
88

9-
driver.find_element(By.ID,"myelt").click_at(100, -100)
9+
```python
10+
driver.find_element(By.ID, "myelt").click_at(100, -100)
11+
```
1012

1113
## Move the cursor over the element
1214

1315
You can move the cursor to the center of the element with the `move_to()` function.
1416

15-
driver.find_element(By.ID,"myelt").move_to()
17+
```python
18+
driver.find_element(By.ID, "myelt").move_to()
19+
```
1620

1721
## Move the cursor with offset
1822

1923
You can move the cursor to a specific location related to the top left corner of the element with the `move_at(xoffset, yoffset)` function.
2024

21-
driver.find_element(By.ID,"myelt").move_at(20, 20)
25+
```python
26+
driver.find_element(By.ID, "myelt").move_at(20, 20)
27+
```

docs/webelement_wait.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
# WebElement excpected conditions
22

3-
Niobium make easier the waiting of expected conditions on a WebElement.
3+
Niobium make easier the waiting of expected conditions on a `WebElement`.
44

55
## Wait until element is displayed and enabled
66

7-
You just have to call the `wait()` function on a WebElement.
7+
You just have to call the `wait()` function on a `WebElement`.
88

9-
driver.find_element(By.ID,"myelt").wait()
9+
```python
10+
driver.find_element(By.ID, "myelt").wait()
11+
```
1012

1113
By default, the timeout is the same the implicitly_wait timeout.
1214

1315
## Wait using a specific timeout
1416

1517
You can specify the maximum time to wait using the `timeout` argument (in seconds).
1618

17-
driver.find_element(By.ID,"myelt").wait(timeout=5)
19+
```python
20+
driver.find_element(By.ID, "myelt").wait(timeout=5)
21+
```
1822

1923
## Choose expected conditions to wait
2024

@@ -27,15 +31,18 @@ Two expected conditions are available:
2731

2832
If value is None, the expected condition is not checked.
2933

30-
driver.find_element(By.ID,"myelt").wait(displayed=False, enabled=False)
31-
32-
driver.find_element(By.ID,"myelt").wait(enabled=False)
34+
```python
35+
driver.find_element(By.ID, "myelt").wait(displayed=False, enabled=False)
3336

37+
driver.find_element(By.ID, "myelt").wait(enabled=False)
38+
```
3439

3540
## Chain action after wait()
3641

3742
You can chain all available actions after the wait.
3843

39-
driver.find_element(By.ID,"myelt").wait(timeout=5).click()
44+
```python
45+
driver.find_element(By.ID, "myelt").wait(timeout=5).click()
46+
```
4047

4148
It's usefull when you have to wait until an element is visible before to click on it.

niobium/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import selenium
2-
from .patch import (
2+
from niobium.patch import (
33
patch_image,
44
patch_timeout,
55
patch_webelement_action,
@@ -13,4 +13,4 @@
1313

1414
__all__ = ["selenium"]
1515

16-
__version__ = "0.4.0"
16+
__version__ = "0.5.0"

niobium/find_image.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
import io
2+
from typing import Optional
3+
from typing import Union
4+
25

36
import cv2
47
import numpy as np
58
from PIL import Image
69
from selenium.common.exceptions import NoSuchElementException
710
from selenium.common.exceptions import WebDriverException
11+
from selenium.webdriver.common.by import By as OriginalBy
812
from selenium.webdriver.remote.webdriver import WebDriver
13+
from selenium.webdriver.remote.webelement import WebElement
14+
15+
16+
from niobium.image_element import ImageElement
17+
from niobium.timeout import ImplicitWait
918

10-
from .image_element import ImageElement
11-
from .timeout import ImplicitWait
19+
original_webdriver_find_element = WebDriver.find_element
20+
original_webdriver_find_elements = WebDriver.find_elements
21+
22+
23+
class By(OriginalBy):
24+
IMAGE = "image"
1225

1326

1427
def match_template(img_src, img_template, threshold=0.9):
@@ -31,7 +44,7 @@ def match_template(img_src, img_template, threshold=0.9):
3144
return []
3245

3346

34-
def find_elements_by_image(self: WebDriver, filename: str):
47+
def find_elements_by_image(self: WebDriver, filename: str) -> list[ImageElement]:
3548
"""
3649
Locate all the occurence of an image in the webpage.
3750
@@ -57,7 +70,7 @@ def find_elements_by_image(self: WebDriver, filename: str):
5770
]
5871

5972

60-
def find_element_by_image(self: WebDriver, filename: str):
73+
def find_element_by_image(self: WebDriver, filename: str) -> ImageElement:
6174
"""
6275
Locate an image in the webpage.
6376
@@ -84,3 +97,21 @@ def find_element_by_image(self: WebDriver, filename: str):
8497
)
8598
else:
8699
return elements[0]
100+
101+
102+
def find_element(
103+
self: WebDriver, by=By.ID, value: Optional[str] = None
104+
) -> Union[WebElement, ImageElement]:
105+
if by == By.IMAGE and value is not None:
106+
return find_element_by_image(self, value)
107+
else:
108+
return original_webdriver_find_element(self, by, value)
109+
110+
111+
def find_elements(
112+
self: WebDriver, by=By.ID, value: Optional[str] = None
113+
) -> Union[list[WebElement], list[ImageElement]]:
114+
if by == By.IMAGE and value is not None:
115+
return find_elements_by_image(self, value)
116+
else:
117+
return original_webdriver_find_elements(self, by, value)

0 commit comments

Comments
 (0)