style: apply ruff format across the codebase

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mathew Sir Guest the best 2026-07-08 23:12:23 -06:00
parent 5ec5ad615a
commit 68978a34e7
10 changed files with 62 additions and 47 deletions

@ -31,9 +31,7 @@ from .pacing import HumanPacing
LOGGER = logging.getLogger("wabot") LOGGER = logging.getLogger("wabot")
# attributes that must never be delegated to the page # attributes that must never be delegated to the page
_OWN_ATTRS = frozenset( _OWN_ATTRS = frozenset({"driver", "pacing", "session_name", "good", "page", "_store"})
{"driver", "pacing", "session_name", "good", "page", "_store"}
)
def _refused(*_args, **_kwargs): def _refused(*_args, **_kwargs):
@ -69,9 +67,7 @@ class Browser:
if name in _OWN_ATTRS or name.startswith("__"): if name in _OWN_ATTRS or name.startswith("__"):
raise AttributeError(name) raise AttributeError(name)
if self.page is None: if self.page is None:
raise AttributeError( raise AttributeError(f"{name!r}: no current page — call set_page() first")
f"{name!r}: no current page — call set_page() first"
)
if not self.good: if not self.good:
LOGGER.warning("broken state — refusing page action %r (call reset())", name) LOGGER.warning("broken state — refusing page action %r (call reset())", name)
return _refused return _refused

@ -72,9 +72,7 @@ class Page:
LOGGER.warning("element not in page map: %s", key) LOGGER.warning("element not in page map: %s", key)
return NullField(name=key) return NullField(name=key)
if not isinstance(locators, (tuple, list)) or len(locators) < 2: if not isinstance(locators, (tuple, list)) or len(locators) < 2:
LOGGER.error( LOGGER.error("malformed element %r: expected (type, accessors), got %r", key, locators)
"malformed element %r: expected (type, accessors), got %r", key, locators
)
return NullField(name=key) return NullField(name=key)
obj_type, accessors = locators[0], locators[1] obj_type, accessors = locators[0], locators[1]
# built-in types need a (by, value) accessors pair; a custom field class # built-in types need a (by, value) accessors pair; a custom field class

@ -26,9 +26,7 @@ def pytest_collection_modifyitems(items):
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def site_url(): def site_url():
"""Serve tests/fixtures over HTTP on an ephemeral port.""" """Serve tests/fixtures over HTTP on an ephemeral port."""
handler = functools.partial( handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=str(FIXTURES))
http.server.SimpleHTTPRequestHandler, directory=str(FIXTURES)
)
server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), handler) server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), handler)
thread = threading.Thread(target=server.serve_forever, daemon=True) thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start() thread.start()

@ -17,7 +17,8 @@ def external_chromedriver():
pytest.skip("chromedriver not on PATH") pytest.skip("chromedriver not on PATH")
proc = subprocess.Popen( proc = subprocess.Popen(
[binary, "--port=19515"], [binary, "--port=19515"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
) )
url = "http://127.0.0.1:19515" url = "http://127.0.0.1:19515"
deadline = time.monotonic() + 15 deadline = time.monotonic() + 15
@ -31,8 +32,12 @@ def external_chromedriver():
def test_persistent_session_on_external_host(external_chromedriver, site_url, store): def test_persistent_session_on_external_host(external_chromedriver, site_url, store):
bot = wabot.browser( bot = wabot.browser(
session="ext", browser="chromium", host=external_chromedriver, session="ext",
headless=True, pacing=wabot.NoPacing(), store=store, browser="chromium",
host=external_chromedriver,
headless=True,
pacing=wabot.NoPacing(),
store=store,
) )
bot.driver.get(f"{site_url}/welcome.html") bot.driver.get(f"{site_url}/welcome.html")
record = store.get("ext") record = store.get("ext")
@ -50,8 +55,11 @@ def test_persistent_session_on_external_host(external_chromedriver, site_url, st
def test_ephemeral_on_external_host(external_chromedriver, site_url, store): def test_ephemeral_on_external_host(external_chromedriver, site_url, store):
bot = wabot.browser( bot = wabot.browser(
host=external_chromedriver, browser="chromium", host=external_chromedriver,
headless=True, pacing=wabot.NoPacing(), store=store, browser="chromium",
headless=True,
pacing=wabot.NoPacing(),
store=store,
) )
bot.driver.get(f"{site_url}/welcome.html") bot.driver.get(f"{site_url}/welcome.html")
assert store.names() == [] # session=None never persists assert store.names() == [] # session=None never persists

@ -28,8 +28,11 @@ REATTACH_SCRIPT = textwrap.dedent(
@pytest.mark.parametrize("browser_name", BROWSERS) @pytest.mark.parametrize("browser_name", BROWSERS)
def test_second_process_picks_up_saved_browser(browser_name, site_url, store, tmp_path): def test_second_process_picks_up_saved_browser(browser_name, site_url, store, tmp_path):
bot = wabot.browser( bot = wabot.browser(
session="flagship", browser=browser_name, headless=True, session="flagship",
pacing=wabot.NoPacing(), store=store, browser=browser_name,
headless=True,
pacing=wabot.NoPacing(),
store=store,
) )
try: try:
bot.driver.get(f"{site_url}/login.html") bot.driver.get(f"{site_url}/login.html")
@ -41,7 +44,10 @@ def test_second_process_picks_up_saved_browser(browser_name, site_url, store, tm
result = subprocess.run( result = subprocess.run(
[sys.executable, "-c", REATTACH_SCRIPT, str(store.path), "flagship"], [sys.executable, "-c", REATTACH_SCRIPT, str(store.path), "flagship"],
capture_output=True, text=True, timeout=120, check=True, capture_output=True,
text=True,
timeout=120,
check=True,
) )
payload = json.loads(result.stdout.strip().splitlines()[-1]) payload = json.loads(result.stdout.strip().splitlines()[-1])
assert payload["url"] == f"{site_url}/login.html" assert payload["url"] == f"{site_url}/login.html"
@ -54,8 +60,11 @@ def test_destroyed_session_is_really_gone(site_url, store):
from wabot.hosts import service_alive from wabot.hosts import service_alive
bot = wabot.browser( bot = wabot.browser(
session="doomed", browser="chromium", headless=True, session="doomed",
pacing=wabot.NoPacing(), store=store, browser="chromium",
headless=True,
pacing=wabot.NoPacing(),
store=store,
) )
bot.driver.get(f"{site_url}/login.html") bot.driver.get(f"{site_url}/login.html")
record = store.get("doomed") record = store.get("doomed")

@ -158,11 +158,17 @@ class TestResourceCleanup:
stopped = [] stopped = []
monkeypatch.setattr(wabot, "stop_service", lambda pid: stopped.append(pid)) monkeypatch.setattr(wabot, "stop_service", lambda pid: stopped.append(pid))
store.save(wabot.SessionRecord( store.save(
name="s1", executor_url="http://127.0.0.1:7777", session_id="old", wabot.SessionRecord(
browser="chromium", created_at=datetime.now(timezone.utc).isoformat(), name="s1",
service_pid=9999, service_port=7777, executor_url="http://127.0.0.1:7777",
)) session_id="old",
browser="chromium",
created_at=datetime.now(timezone.utc).isoformat(),
service_pid=9999,
service_port=7777,
)
)
fake_selenium.service_alive.return_value = True fake_selenium.service_alive.return_value = True
fake_selenium.attach.return_value = None # session dead on a live server fake_selenium.attach.return_value = None # session dead on a live server
wabot.browser(session="s1", store=store) wabot.browser(session="s1", store=store)
@ -176,8 +182,11 @@ class TestDestroyEdges:
from datetime import datetime, timezone from datetime import datetime, timezone
defaults = dict( defaults = dict(
name="s1", executor_url="http://127.0.0.1:7777", session_id="old", name="s1",
browser="chromium", created_at=datetime.now(timezone.utc).isoformat(), executor_url="http://127.0.0.1:7777",
session_id="old",
browser="chromium",
created_at=datetime.now(timezone.utc).isoformat(),
) )
defaults.update(kw) defaults.update(kw)
store.save(wabot.SessionRecord(**defaults)) store.save(wabot.SessionRecord(**defaults))

@ -97,7 +97,7 @@ class TestPerform:
bot.set_page(Login) bot.set_page(Login)
bot.perform("explode") bot.perform("explode")
assert bot.perform("do_login") is None # refused assert bot.perform("do_login") is None # refused
assert bot.do_login() is None # __getattr__ path also refused assert bot.do_login() is None # __getattr__ path also refused
bot.reset() bot.reset()
assert bot.perform("do_login") == "logged-in" assert bot.perform("do_login") == "logged-in"

@ -73,9 +73,7 @@ class TestGetProxy:
browser = make_browser() browser = make_browser()
page = BasePage(browser) page = BasePage(browser)
result = page["rows"] result = page["rows"]
browser.driver.find_elements.assert_called_once_with( browser.driver.find_elements.assert_called_once_with(by="css selector", value="tr.row")
by="css selector", value="tr.row"
)
assert result is browser.driver.find_elements.return_value assert result is browser.driver.find_elements.return_value
def test_unknown_key_returns_falsy_nullfield(self): def test_unknown_key_returns_falsy_nullfield(self):

@ -16,9 +16,7 @@ class TestReattachingRemote:
assert isinstance(driver.caps, dict) assert isinstance(driver.caps, dict)
def test_works_for_firefox_options_too(self): def test_works_for_firefox_options_too(self):
driver = ReattachingRemote( driver = ReattachingRemote("http://127.0.0.1:1", "sid", options=build_options("firefox"))
"http://127.0.0.1:1", "sid", options=build_options("firefox")
)
assert driver.session_id == "sid" assert driver.session_id == "sid"

@ -62,7 +62,8 @@ class TestChromiumPath:
assert Image.open(out).size == (100, 150) assert Image.open(out).size == (100, 150)
# scrolled at least twice beyond the initial position # scrolled at least twice beyond the initial position
scroll_calls = [ scroll_calls = [
c for c in driver.execute_script.call_args_list c
for c in driver.execute_script.call_args_list
if c.args and str(c.args[0]).startswith("window.scrollTo") if c.args and str(c.args[0]).startswith("window.scrollTo")
] ]
assert len(scroll_calls) >= 2 assert len(scroll_calls) >= 2
@ -77,17 +78,17 @@ class TestChromiumPath:
"return window.innerHeight": 60, "return window.innerHeight": 60,
}.get(script) # window.scrollTo(...) -> None }.get(script) # window.scrollTo(...) -> None
driver.get_screenshot_as_png.side_effect = [ driver.get_screenshot_as_png.side_effect = [
png_bytes(100, 60, (255, 0, 0)), # tile @ y=0 png_bytes(100, 60, (255, 0, 0)), # tile @ y=0
png_bytes(100, 60, (0, 255, 0)), # tile @ y=60 png_bytes(100, 60, (0, 255, 0)), # tile @ y=60
png_bytes(100, 60, (0, 0, 255)), # tile @ y=120, clamped to paste_y=90 png_bytes(100, 60, (0, 0, 255)), # tile @ y=120, clamped to paste_y=90
] ]
out = tmp_path / "shot.png" out = tmp_path / "shot.png"
assert save_full_page(driver, str(out)) is True assert save_full_page(driver, str(out)) is True
img = Image.open(out) img = Image.open(out)
assert img.size == (100, 150) assert img.size == (100, 150)
assert img.getpixel((50, 30)) == (255, 0, 0) # first tile assert img.getpixel((50, 30)) == (255, 0, 0) # first tile
assert img.getpixel((50, 75)) == (0, 255, 0) # second tile (rows 60-89) assert img.getpixel((50, 75)) == (0, 255, 0) # second tile (rows 60-89)
assert img.getpixel((50, 140)) == (0, 0, 255) # third tile, bottom-aligned assert img.getpixel((50, 140)) == (0, 0, 255) # third tile, bottom-aligned
def test_wide_page_clamps_last_column(self, tmp_path): def test_wide_page_clamps_last_column(self, tmp_path):
driver = MagicMock(name="driver") driver = MagicMock(name="driver")
@ -99,12 +100,12 @@ class TestChromiumPath:
"return window.innerHeight": 60, "return window.innerHeight": 60,
}.get(script) }.get(script)
driver.get_screenshot_as_png.side_effect = [ driver.get_screenshot_as_png.side_effect = [
png_bytes(100, 60, (255, 0, 0)), # column @ x=0 png_bytes(100, 60, (255, 0, 0)), # column @ x=0
png_bytes(100, 60, (0, 0, 255)), # column @ x=100, clamped to paste_x=50 png_bytes(100, 60, (0, 0, 255)), # column @ x=100, clamped to paste_x=50
] ]
out = tmp_path / "shot.png" out = tmp_path / "shot.png"
assert save_full_page(driver, str(out)) is True assert save_full_page(driver, str(out)) is True
img = Image.open(out) img = Image.open(out)
assert img.size == (150, 60) assert img.size == (150, 60)
assert img.getpixel((25, 30)) == (255, 0, 0) # left column (cols 0-49) assert img.getpixel((25, 30)) == (255, 0, 0) # left column (cols 0-49)
assert img.getpixel((140, 30)) == (0, 0, 255) # right column, clamped (cols 50-149) assert img.getpixel((140, 30)) == (0, 0, 255) # right column, clamped (cols 50-149)