Skip to content

Commit

Permalink
using Self now that it's available in typing_extensions (ScreenPyHQ#48
Browse files Browse the repository at this point in the history
)

* using `Self` now that it's available in typing_extensions
* updated ruff configuration to move all possible imports into TYPE_CHECKING
  • Loading branch information
bandophahita authored Feb 15, 2024
1 parent dd85ed2 commit a6eed1a
Show file tree
Hide file tree
Showing 28 changed files with 370 additions and 480 deletions.
18 changes: 5 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,10 @@ local_screenpy:
black-check:
black --check .

black:
black-fix:
black .

isort-check:
isort . --check

isort:
isort .

ruff:
ruff-check:
ruff check .

ruff-fix:
Expand All @@ -41,12 +35,10 @@ ruff-fix:
mypy:
mypy .

lint: isort-check ruff mypy

.PHONY: black-check black isort-check isort ruff ruff-fix mypy lint
.PHONY: black-check black-fix ruff-check ruff-fix mypy

pre-check-in: black-check lint
pre-check-in: black-check ruff-check mypy

pre-check-in-fix: black isort ruff-fix mypy
pre-check-in-fix: black-fix ruff-fix mypy

.PHONY: pre-check-in pre-check-in-fix
282 changes: 134 additions & 148 deletions poetry.lock

Large diffs are not rendered by default.

23 changes: 4 additions & 19 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ importlib_metadata = {version = "*", python = "3.8.*"}
# convenience packages for development of screenpy only
black = {version = "*", optional = true}
coverage = {version = "*", optional = true}
isort = {version = "*", optional = true}
mypy = {version = "*", optional = true}
pre-commit = {version = "*", optional = true}
pytest = {version = "*", optional = true}
Expand All @@ -86,7 +85,6 @@ dev = [
dev_all = [
"black",
"coverage",
"isort",
"mypy",
"pre-commit",
"pytest",
Expand Down Expand Up @@ -166,14 +164,11 @@ extend-safe-fixes = [
"EM101",
"EM102",
"TCH001", "TCH002", "TCH003", "TCH004",
# "SIM108"
# maybe?
# "F841",
"C419",
"D200", "D205", "D415",
"PT003", "PT006", "PT018",
"RET504",
"UP007",
"UP006", "UP007",
]

[tool.ruff.lint.per-file-ignores]
Expand All @@ -182,13 +177,10 @@ extend-safe-fixes = [
"FBT", # using a boolean as a test object is useful!
"PLR", # likewise using specific numbers and strings in tests.
]
"tests/test_pacing.py" = [
"FA100", # we are purposely testing pacing without future annotations.
]

[tool.ruff.lint.isort]
combine-as-imports = true
split-on-trailing-comma = true
split-on-trailing-comma = false
known-first-party = ["screenpy_selenium", "tests"]


Expand All @@ -204,12 +196,5 @@ ignore-overlong-task-comments = true
convention = "google"


[tool.isort]
line_length = 88
multi_line_output = 3
include_trailing_comma = true
use_parentheses = true
combine_as_imports = true

skip = [".idea", ".tox", "docs"]
src_paths = ["screenpy_selenium","tests"]
[tool.ruff.lint.flake8-type-checking]
strict = true
24 changes: 11 additions & 13 deletions screenpy_selenium/abilities/browse_the_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
from __future__ import annotations

import os
from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING

from selenium.webdriver import Chrome, Firefox, Remote, Safari

from ..exceptions import BrowsingError

if TYPE_CHECKING:
from selenium.webdriver.remote.webdriver import WebDriver
from typing_extensions import Self

DEFAULT_APPIUM_HUB_URL = "http://localhost:4723/wd/hub"


SelfBrowseTheWeb = TypeVar("SelfBrowseTheWeb", bound="BrowseTheWeb")


class BrowseTheWeb:
"""Use Selenium to enable browsing the web with a web browser.
Expand All @@ -35,22 +33,22 @@ class BrowseTheWeb:
browser: WebDriver

@classmethod
def using_chrome(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
def using_chrome(cls) -> Self:
"""Create and use a default Chrome Selenium webdriver instance."""
return cls.using(browser=Chrome())

@classmethod
def using_firefox(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
def using_firefox(cls) -> Self:
"""Create and use a default Firefox Selenium webdriver instance."""
return cls.using(browser=Firefox())

@classmethod
def using_safari(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
def using_safari(cls) -> Self:
"""Create and use a default Safari Selenium webdriver instance."""
return cls.using(browser=Safari())

@classmethod
def using_ios(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
def using_ios(cls) -> Self:
"""
Create and use a default Remote driver instance.
Expand Down Expand Up @@ -83,7 +81,7 @@ def using_ios(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
return cls.using(browser=Remote(hub_url, IOS_CAPABILITIES))

@classmethod
def using_android(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
def using_android(cls) -> Self:
"""
Create and use a default Remote driver instance.
Expand Down Expand Up @@ -116,19 +114,19 @@ def using_android(cls: type[SelfBrowseTheWeb]) -> SelfBrowseTheWeb:
return cls.using(browser=Remote(hub_url, ANDROID_CAPABILITIES))

@classmethod
def using(cls: type[SelfBrowseTheWeb], browser: WebDriver) -> SelfBrowseTheWeb:
def using(cls, browser: WebDriver) -> Self:
"""Provide an already-set-up WebDriver to use to browse the web."""
return cls(browser=browser)

def forget(self: SelfBrowseTheWeb) -> None:
def forget(self) -> None:
"""Quit the attached browser."""
self.browser.quit()

def __repr__(self: SelfBrowseTheWeb) -> str:
def __repr__(self) -> str:
"""Repr."""
return "Browse the Web"

__str__ = __repr__

def __init__(self: SelfBrowseTheWeb, browser: WebDriver) -> None:
def __init__(self, browser: WebDriver) -> None:
self.browser = browser
19 changes: 8 additions & 11 deletions screenpy_selenium/actions/clear.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

from __future__ import annotations

from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING

from screenpy.exceptions import DeliveryError
from screenpy.pacing import beat
from selenium.common.exceptions import WebDriverException

if TYPE_CHECKING:
from screenpy.actor import Actor
from typing_extensions import Self

from ..target import Target

SelfClear = TypeVar("SelfClear", bound="Clear")


class Clear:
"""Clear the text from an input field.
Expand All @@ -28,7 +27,7 @@ class Clear:
"""

@classmethod
def the_text_from_the(cls: type[SelfClear], target: Target) -> SelfClear:
def the_text_from_the(cls, target: Target) -> Self:
"""
Specify the Target from which to clear the text.
Expand All @@ -39,23 +38,21 @@ def the_text_from_the(cls: type[SelfClear], target: Target) -> SelfClear:
return cls(target=target)

@classmethod
def the_text_from(cls: type[SelfClear], target: Target) -> SelfClear:
def the_text_from(cls, target: Target) -> Self:
"""Alias for :meth:`~screenpy_selenium.actions.Clear.the_text_from_the`."""
return cls.the_text_from_the(target=target)

@classmethod
def the_text_from_the_first_of_the(
cls: type[SelfClear], target: Target
) -> SelfClear:
def the_text_from_the_first_of_the(cls, target: Target) -> Self:
"""Alias for :meth:`~screenpy_selenium.actions.Clear.the_text_from_the`."""
return cls.the_text_from_the(target=target)

def describe(self: SelfClear) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"Clear the text from the {self.target}."

@beat("{} clears text from the {target}.")
def perform_as(self: SelfClear, the_actor: Actor) -> None:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to clear the text from the input field."""
element = self.target.found_by(the_actor)

Expand All @@ -68,5 +65,5 @@ def perform_as(self: SelfClear, the_actor: Actor) -> None:
)
raise DeliveryError(msg) from e

def __init__(self: SelfClear, target: Target) -> None:
def __init__(self, target: Target) -> None:
self.target = target
21 changes: 9 additions & 12 deletions screenpy_selenium/actions/click.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING

from screenpy.exceptions import DeliveryError, UnableToAct
from screenpy.pacing import beat
Expand All @@ -11,11 +11,10 @@
if TYPE_CHECKING:
from screenpy.actor import Actor
from selenium.webdriver.common.action_chains import ActionChains
from typing_extensions import Self

from ..target import Target

SelfClick = TypeVar("SelfClick", bound="Click")


class Click:
"""Click on an element!
Expand All @@ -33,7 +32,7 @@ class Click:
"""

@classmethod
def on_the(cls: type[SelfClick], target: Target) -> SelfClick:
def on_the(cls, target: Target) -> Self:
"""
Target the element to click on.
Expand All @@ -44,21 +43,21 @@ def on_the(cls: type[SelfClick], target: Target) -> SelfClick:
return cls(target=target)

@classmethod
def on(cls: type[SelfClick], target: Target) -> SelfClick:
def on(cls, target: Target) -> Self:
"""Alias for :meth:`~screenpy_selenium.actions.Click.on_the`."""
return cls.on_the(target=target)

@classmethod
def on_the_first_of_the(cls: type[SelfClick], target: Target) -> SelfClick:
def on_the_first_of_the(cls, target: Target) -> Self:
"""Alias for :meth:`~screenpy_selenium.actions.Click.on_the`."""
return cls.on_the(target=target)

def describe(self: SelfClick) -> str:
def describe(self) -> str:
"""Describe the Action in present tense."""
return f"Click on the {self.target}."

@beat("{} clicks on the {target}.")
def perform_as(self: SelfClick, the_actor: Actor) -> None:
def perform_as(self, the_actor: Actor) -> None:
"""Direct the Actor to click on the element."""
if self.target is None:
msg = (
Expand All @@ -79,9 +78,7 @@ def perform_as(self: SelfClick, the_actor: Actor) -> None:
raise DeliveryError(msg) from e

@beat("Click{description}!")
def add_to_chain(
self: SelfClick, the_actor: Actor, the_chain: ActionChains
) -> None:
def add_to_chain(self, the_actor: Actor, the_chain: ActionChains) -> None:
"""Add the Click Action to a Chain of Actions."""
if self.target is not None:
the_element = self.target.found_by(the_actor)
Expand All @@ -90,6 +87,6 @@ def add_to_chain(

the_chain.click(on_element=the_element)

def __init__(self: SelfClick, target: Target | None = None) -> None:
def __init__(self, target: Target | None = None) -> None:
self.target = target
self.description = f" on the {target}" if target is not None else ""
Loading

0 comments on commit a6eed1a

Please sign in to comment.