Skip to content

Commit d213766

Browse files
committed
Add type hints to SL keywords
1 parent 40b302e commit d213766

16 files changed

+213
-254
lines changed

atest/acceptance/keywords/counting_elements.robot

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,6 @@ Resource ../resource.robot
55
Library String
66

77
*** Test Cases ***
8-
Locator Should Match X Times
9-
[Documentation] Deprecated
10-
[Setup] Go To Page "links.html"
11-
Locator Should Match X Times link=Link 2
12-
Locator Should Match X Times link=Missing Link 0
13-
Locator Should Match X Times name:div_name 2
14-
Locator Should Match X Times xpath://*[@name="div_name"] 2
15-
16-
Locator Should Match X Times Error
17-
[Documentation] Deprecated
18-
[Setup] Go To Page "links.html"
19-
Run Keyword And Expect Error
20-
... Locator 'name: div_name' should have matched 3 times but matched 2 times.
21-
... Locator Should Match X Times name: div_name 3
22-
Run Keyword And Expect Error
23-
... Custom error ÄÄÄ
24-
... Locator Should Match X Times name:div_name 3 Custom error ÄÄÄ
25-
268
Get Element Count With Xpath Locator
279
[Setup] Go To Page "links.html"
2810
${count} = Get Element Count xpath://*[@name="div_name"]
@@ -75,7 +57,7 @@ Page Should Contain Element When Limit Is Number And Error
7557
Page Should Contain Element When Limit Is Not Number
7658
[Setup] Go To Page "links.html"
7759
Run Keyword And Expect Error
78-
... ValueError: invalid literal for int() with base 10: 'AA'
60+
... ValueError: *Argument 'limit' got value 'AA'*
7961
... Page Should Contain Element name: div_name limit=AA
8062

8163
Page Should Contain Element When Error With Limit And Different Loglevels

src/SeleniumLibrary/keywords/alert.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
16+
from typing import Optional, Union
1617

1718
from selenium.common.exceptions import TimeoutException, WebDriverException
1819
from selenium.webdriver.support import expected_conditions as EC
@@ -29,7 +30,7 @@ class AlertKeywords(LibraryComponent):
2930
_next_alert_action = ACCEPT
3031

3132
@keyword
32-
def input_text_into_alert(self, text, action=ACCEPT, timeout=None):
33+
def input_text_into_alert(self, text: str, action: str = ACCEPT, timeout: Union[float, str, None] = None):
3334
"""Types the given ``text`` into an input field in an alert.
3435
3536
The alert is accepted by default, but that behavior can be controlled
@@ -45,7 +46,7 @@ def input_text_into_alert(self, text, action=ACCEPT, timeout=None):
4546
self._handle_alert(alert, action)
4647

4748
@keyword
48-
def alert_should_be_present(self, text="", action=ACCEPT, timeout=None):
49+
def alert_should_be_present(self, text: str = "", action: str = ACCEPT, timeout: Union[float, str, None] = None):
4950
"""Verifies that an alert is present and by default, accepts it.
5051
5152
Fails if no alert is present. If ``text`` is a non-empty string,
@@ -67,7 +68,7 @@ def alert_should_be_present(self, text="", action=ACCEPT, timeout=None):
6768
)
6869

6970
@keyword
70-
def alert_should_not_be_present(self, action=ACCEPT, timeout=0):
71+
def alert_should_not_be_present(self, action: str = ACCEPT, timeout: Union[float, str, None] = 0):
7172
"""Verifies that no alert is present.
7273
7374
If the alert actually exists, the ``action`` argument determines
@@ -90,7 +91,7 @@ def alert_should_not_be_present(self, action=ACCEPT, timeout=0):
9091
raise AssertionError(f"Alert with message '{text}' present.")
9192

9293
@keyword
93-
def handle_alert(self, action=ACCEPT, timeout=None):
94+
def handle_alert(self, action: str = ACCEPT, timeout: Union[float, str, None] = None):
9495
"""Handles the current alert and returns its message.
9596
9697
By default, the alert is accepted, but this can be controlled

src/SeleniumLibrary/keywords/browsermanagement.py

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import time
1818
import types
19+
from typing import Optional, Union, Any, List
1920

2021
from selenium import webdriver
2122
from selenium.webdriver.support.event_firing_webdriver import EventFiringWebDriver
@@ -56,16 +57,16 @@ def close_browser(self):
5657
@keyword
5758
def open_browser(
5859
self,
59-
url=None,
60-
browser="firefox",
61-
alias=None,
62-
remote_url=False,
63-
desired_capabilities=None,
64-
ff_profile_dir=None,
65-
options=None,
66-
service_log_path=None,
67-
executable_path=None,
68-
):
60+
url: Optional[str] = None,
61+
browser: str = "firefox",
62+
alias: Optional[str] = None,
63+
remote_url: Optional[str] = False,
64+
desired_capabilities: Union[str, dict, None] = None,
65+
ff_profile_dir: Optional[str] = None,
66+
options: Any = None,
67+
service_log_path: Optional[str] = None,
68+
executable_path: Optional[str] = None,
69+
) -> str:
6970
"""Opens a new browser instance to the optional ``url``.
7071
7172
The ``browser`` argument specifies which browser to use. The
@@ -341,7 +342,7 @@ def _make_new_browser(
341342
return index
342343

343344
@keyword
344-
def create_webdriver(self, driver_name, alias=None, kwargs={}, **init_kwargs):
345+
def create_webdriver(self, driver_name: str, alias: Optional[str] = None, kwargs={}, **init_kwargs) -> str:
345346
"""Creates an instance of Selenium WebDriver.
346347
347348
Like `Open Browser`, but allows passing arguments to the created
@@ -397,7 +398,7 @@ def _wrap_event_firing_webdriver(self, driver):
397398
return EventFiringWebDriver(driver, self.ctx.event_firing_webdriver())
398399

399400
@keyword
400-
def switch_browser(self, index_or_alias):
401+
def switch_browser(self, index_or_alias: str):
401402
"""Switches between active browsers using ``index_or_alias``.
402403
403404
Indices are returned by the `Open Browser` keyword and aliases can
@@ -434,7 +435,7 @@ def switch_browser(self, index_or_alias):
434435
)
435436

436437
@keyword
437-
def get_browser_ids(self):
438+
def get_browser_ids(self) -> List[str]:
438439
"""Returns index of all active browser as list.
439440
440441
Example:
@@ -451,7 +452,7 @@ def get_browser_ids(self):
451452
return self.drivers.active_driver_ids
452453

453454
@keyword
454-
def get_browser_aliases(self):
455+
def get_browser_aliases(self) -> List[str]:
455456
"""Returns aliases of all active browser that has an alias as NormalizedDict.
456457
The dictionary contains the aliases as keys and the index as value.
457458
This can be accessed as dictionary ``${aliases.key}`` or as list ``@{aliases}[0]``.
@@ -472,30 +473,30 @@ def get_browser_aliases(self):
472473
return self.drivers.active_aliases
473474

474475
@keyword
475-
def get_session_id(self):
476+
def get_session_id(self) -> str:
476477
"""Returns the currently active browser session id.
477478
478479
New in SeleniumLibrary 3.2
479480
"""
480481
return self.driver.session_id
481482

482483
@keyword
483-
def get_source(self):
484+
def get_source(self) -> str:
484485
"""Returns the entire HTML source of the current page or frame."""
485486
return self.driver.page_source
486487

487488
@keyword
488-
def get_title(self):
489+
def get_title(self) -> str:
489490
"""Returns the title of the current page."""
490491
return self.driver.title
491492

492493
@keyword
493-
def get_location(self):
494+
def get_location(self) -> str:
494495
"""Returns the current browser window URL."""
495496
return self.driver.current_url
496497

497498
@keyword
498-
def location_should_be(self, url, message=None):
499+
def location_should_be(self, url: str, message: Optional[str] = None):
499500
"""Verifies that the current URL is exactly ``url``.
500501
501502
The ``url`` argument contains the exact url that should exist in browser.
@@ -513,7 +514,7 @@ def location_should_be(self, url, message=None):
513514
self.info(f"Current location is '{url}'.")
514515

515516
@keyword
516-
def location_should_contain(self, expected, message=None):
517+
def location_should_contain(self, expected: str, message: Optional[str] = None):
517518
"""Verifies that the current URL contains ``expected``.
518519
519520
The ``expected`` argument contains the expected value in url.
@@ -534,14 +535,14 @@ def location_should_contain(self, expected, message=None):
534535
self.info(f"Current location contains '{expected}'.")
535536

536537
@keyword
537-
def log_location(self):
538+
def log_location(self) -> str:
538539
"""Logs and returns the current browser window URL."""
539540
url = self.get_location()
540541
self.info(url)
541542
return url
542543

543544
@keyword
544-
def log_source(self, loglevel="INFO"):
545+
def log_source(self, loglevel: str = "INFO") -> str:
545546
"""Logs and returns the HTML source of the current page or frame.
546547
547548
The ``loglevel`` argument defines the used log level. Valid log
@@ -553,14 +554,14 @@ def log_source(self, loglevel="INFO"):
553554
return source
554555

555556
@keyword
556-
def log_title(self):
557+
def log_title(self) -> str:
557558
"""Logs and returns the title of the current page."""
558559
title = self.get_title()
559560
self.info(title)
560561
return title
561562

562563
@keyword
563-
def title_should_be(self, title, message=None):
564+
def title_should_be(self, title: str, message: Optional[str] = None):
564565
"""Verifies that the current page title equals ``title``.
565566
566567
The ``message`` argument can be used to override the default error
@@ -592,7 +593,7 @@ def reload_page(self):
592593
self.driver.refresh()
593594

594595
@keyword
595-
def get_selenium_speed(self):
596+
def get_selenium_speed(self) -> str:
596597
"""Gets the delay that is waited after each Selenium command.
597598
598599
The value is returned as a human-readable string like ``1 second``.
@@ -602,7 +603,7 @@ def get_selenium_speed(self):
602603
return secs_to_timestr(self.ctx.speed)
603604

604605
@keyword
605-
def get_selenium_timeout(self):
606+
def get_selenium_timeout(self) -> str:
606607
"""Gets the timeout that is used by various keywords.
607608
608609
The value is returned as a human-readable string like ``1 second``.
@@ -612,7 +613,7 @@ def get_selenium_timeout(self):
612613
return secs_to_timestr(self.ctx.timeout)
613614

614615
@keyword
615-
def get_selenium_implicit_wait(self):
616+
def get_selenium_implicit_wait(self) -> str:
616617
"""Gets the implicit wait value used by Selenium.
617618
618619
The value is returned as a human-readable string like ``1 second``.
@@ -622,7 +623,7 @@ def get_selenium_implicit_wait(self):
622623
return secs_to_timestr(self.ctx.implicit_wait)
623624

624625
@keyword
625-
def set_selenium_speed(self, value):
626+
def set_selenium_speed(self, value: str) -> str:
626627
"""Sets the delay that is waited after each Selenium command.
627628
628629
The value can be given as a number that is considered to be
@@ -642,7 +643,7 @@ def set_selenium_speed(self, value):
642643
return old_speed
643644

644645
@keyword
645-
def set_selenium_timeout(self, value):
646+
def set_selenium_timeout(self, value: str) -> str:
646647
"""Sets the timeout that is used by various keywords.
647648
648649
The value can be given as a number that is considered to be
@@ -664,7 +665,7 @@ def set_selenium_timeout(self, value):
664665
return old_timeout
665666

666667
@keyword
667-
def set_selenium_implicit_wait(self, value):
668+
def set_selenium_implicit_wait(self, value: str) -> str:
668669
"""Sets the implicit wait value used by Selenium.
669670
670671
The value can be given as a number that is considered to be
@@ -690,7 +691,7 @@ def set_selenium_implicit_wait(self, value):
690691
return old_wait
691692

692693
@keyword
693-
def set_browser_implicit_wait(self, value):
694+
def set_browser_implicit_wait(self, value: str):
694695
"""Sets the implicit wait value used by Selenium.
695696
696697
Same as `Set Selenium Implicit Wait` but only affects the current

src/SeleniumLibrary/keywords/cookie.py

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# limitations under the License.
1616

1717
from datetime import datetime
18+
from typing import Union, Optional
1819

1920
from robot.libraries.DateTime import convert_date
2021
from robot.utils import DotDict
@@ -24,6 +25,35 @@
2425
from SeleniumLibrary.utils import is_truthy, is_noney, is_falsy
2526

2627

28+
class CookieInformation:
29+
def __init__(
30+
self,
31+
name,
32+
value,
33+
path=None,
34+
domain=None,
35+
secure=False,
36+
httpOnly=False,
37+
expiry=None,
38+
**extra,
39+
):
40+
self.name = name
41+
self.value = value
42+
self.path = path
43+
self.domain = domain
44+
self.secure = secure
45+
self.httpOnly = httpOnly
46+
self.expiry = datetime.fromtimestamp(expiry) if expiry else None
47+
self.extra = extra
48+
49+
def __str__(self):
50+
items = "name value path domain secure httpOnly expiry".split()
51+
string = "\n".join(f"{item}={getattr(self, item)}" for item in items)
52+
if self.extra:
53+
string = f"{string}\nextra={self.extra}\n"
54+
return string
55+
56+
2757
class CookieKeywords(LibraryComponent):
2858
@keyword
2959
def delete_all_cookies(self):
@@ -39,7 +69,7 @@ def delete_cookie(self, name):
3969
self.driver.delete_cookie(name)
4070

4171
@keyword
42-
def get_cookies(self, as_dict=False):
72+
def get_cookies(self, as_dict: bool = False) -> Union[str, dict]:
4373
"""Returns all cookies of the current page.
4474
4575
If ``as_dict`` argument evaluates as false, see `Boolean arguments`
@@ -66,7 +96,7 @@ def get_cookies(self, as_dict=False):
6696
return pairs
6797

6898
@keyword
69-
def get_cookie(self, name):
99+
def get_cookie(self, name: str) -> CookieInformation:
70100
"""Returns information of cookie with ``name`` as an object.
71101
72102
If no cookie is found with ``name``, keyword fails. The cookie object
@@ -112,7 +142,7 @@ def get_cookie(self, name):
112142
return CookieInformation(**cookie)
113143

114144
@keyword
115-
def add_cookie(self, name, value, path=None, domain=None, secure=None, expiry=None):
145+
def add_cookie(self, name: str, value: str, path: Optional[str] = None, domain: Optional[str] = None, secure: Optional[str] = None, expiry: Optional[str] = None):
116146
"""Adds a cookie to your current session.
117147
118148
``name`` and ``value`` are required, ``path``, ``domain``, ``secure``
@@ -145,32 +175,3 @@ def _expiry(self, expiry):
145175
return int(expiry)
146176
except ValueError:
147177
return int(convert_date(expiry, result_format="epoch"))
148-
149-
150-
class CookieInformation:
151-
def __init__(
152-
self,
153-
name,
154-
value,
155-
path=None,
156-
domain=None,
157-
secure=False,
158-
httpOnly=False,
159-
expiry=None,
160-
**extra,
161-
):
162-
self.name = name
163-
self.value = value
164-
self.path = path
165-
self.domain = domain
166-
self.secure = secure
167-
self.httpOnly = httpOnly
168-
self.expiry = datetime.fromtimestamp(expiry) if expiry else None
169-
self.extra = extra
170-
171-
def __str__(self):
172-
items = "name value path domain secure httpOnly expiry".split()
173-
string = "\n".join(f"{item}={getattr(self, item)}" for item in items)
174-
if self.extra:
175-
string = f"{string}\nextra={self.extra}\n"
176-
return string

0 commit comments

Comments
 (0)