repld-tool 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {repld_tool-0.2.2 → repld_tool-0.2.3}/PKG-INFO +1 -1
- {repld_tool-0.2.2 → repld_tool-0.2.3}/pyproject.toml +1 -1
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/tab.py +39 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/help.py +9 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/LICENSE +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/README.md +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/.ruff_cache/.gitignore +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/.ruff_cache/0.15.22/14226964882126921391 +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/.ruff_cache/CACHEDIR.TAG +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/__init__.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/__main__.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/bg.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/bind.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/bridge.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/bridge_tools.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/__init__.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/browser.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/capture.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/cdp.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/har.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/observe.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/pin.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/png.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/pool.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/row.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/selector.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/session.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/tab_query.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser/target.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/browser_dispatch.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/channel.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/cli.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/cli_args.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/core_schemas.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/dashboard.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/dashboard_cmd.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/dashboard_html.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/display.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/eventlog.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/events.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/exec_cmd.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gate_cmd.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gates.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gist_api.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gist_cmd.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gist_deps.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gist_links.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gist_lint.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/gists.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/ipc.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/kernel.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/kernel_context.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/lifecycle_cmd.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/log_cmd.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/paths.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/protocol.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/relaunch.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/render.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/runtime.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/sessions.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/spawn.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/state.py +0 -0
- {repld_tool-0.2.2 → repld_tool-0.2.3}/src/repld/tasks.py +0 -0
|
@@ -481,6 +481,40 @@ class Tab(TabQueryMixin):
|
|
|
481
481
|
) from reattach_exc
|
|
482
482
|
return await self._session.execute(method, params, timeout)
|
|
483
483
|
|
|
484
|
+
async def _ensure_front(self) -> None:
|
|
485
|
+
"""Raise this tab if Chrome has it backgrounded, before dispatching input.
|
|
486
|
+
|
|
487
|
+
`click`/`tap`/`type_text`/`key` all ride `Input.dispatch*Event` —
|
|
488
|
+
the renderer's real input pipeline, which Chrome silently drops for
|
|
489
|
+
a tab whose window is occluded or backgrounded
|
|
490
|
+
(`document.visibilityState === "hidden"`): the CDP command still
|
|
491
|
+
acks, no exception is raised, and no handler on the page ever
|
|
492
|
+
fires. Resolving a selector doesn't hit this — `DOM.getContentQuads`
|
|
493
|
+
and `Runtime.evaluate` both work fine on a hidden tab, which is why
|
|
494
|
+
the failure looks like nothing happened rather than an error. Costs
|
|
495
|
+
one `Runtime.evaluate` round trip on every call and `Page.bringToFront`
|
|
496
|
+
only on the degraded path — the multi-window watch workflow this
|
|
497
|
+
kernel exists for means N-1 tabs are hidden at any given time, so
|
|
498
|
+
this can't be opt-in.
|
|
499
|
+
"""
|
|
500
|
+
result = await self._exec(
|
|
501
|
+
"Runtime.evaluate",
|
|
502
|
+
{"expression": "document.visibilityState", "returnByValue": True},
|
|
503
|
+
)
|
|
504
|
+
if result.get("result", {}).get("value") == "hidden":
|
|
505
|
+
await self._exec("Page.bringToFront")
|
|
506
|
+
|
|
507
|
+
async def front(self) -> None:
|
|
508
|
+
"""Bring this tab's window to the front (Page.bringToFront).
|
|
509
|
+
|
|
510
|
+
click()/tap()/type_text()/key() already do this automatically when
|
|
511
|
+
the tab is backgrounded — call this directly to raise a tab for its
|
|
512
|
+
own sake (e.g. before a screenshot a human is watching for), or to
|
|
513
|
+
avoid paying the visibility check on every call in a script that
|
|
514
|
+
knows it's about to do a lot of input against one tab.
|
|
515
|
+
"""
|
|
516
|
+
await self._exec("Page.bringToFront")
|
|
517
|
+
|
|
484
518
|
# ------------------------------------------------------------------
|
|
485
519
|
|
|
486
520
|
async def js(
|
|
@@ -643,6 +677,7 @@ class Tab(TabQueryMixin):
|
|
|
643
677
|
|
|
644
678
|
Selector: CSS, text=Label, role=button[name='OK'], or tag:has-text('...')
|
|
645
679
|
"""
|
|
680
|
+
await self._ensure_front()
|
|
646
681
|
x, y = await self._element_center(selector)
|
|
647
682
|
|
|
648
683
|
for event_type in ("mousePressed", "mouseReleased"):
|
|
@@ -670,6 +705,7 @@ class Tab(TabQueryMixin):
|
|
|
670
705
|
Selects all existing content then types over it.
|
|
671
706
|
Selector: CSS, text=Label, role=textbox, label=Name, or tag:has-text('...')
|
|
672
707
|
"""
|
|
708
|
+
await self._ensure_front()
|
|
673
709
|
node_id, js_expr = await self._wait_for_node(selector)
|
|
674
710
|
|
|
675
711
|
if node_id:
|
|
@@ -712,6 +748,7 @@ class Tab(TabQueryMixin):
|
|
|
712
748
|
|
|
713
749
|
async def key(self, key: str) -> None:
|
|
714
750
|
"""Dispatch a keyDown+keyUp pair for a named key (e.g. "Enter", "Escape")."""
|
|
751
|
+
await self._ensure_front()
|
|
715
752
|
for event_type in ("keyDown", "keyUp"):
|
|
716
753
|
await self._exec(
|
|
717
754
|
"Input.dispatchKeyEvent",
|
|
@@ -735,6 +772,7 @@ class Tab(TabQueryMixin):
|
|
|
735
772
|
Uses Input.dispatchTouchEvent — triggers touchstart/touchend listeners
|
|
736
773
|
that dispatchMouseEvent won't reach. Use for mobile Chrome via ADB.
|
|
737
774
|
"""
|
|
775
|
+
await self._ensure_front()
|
|
738
776
|
if y is not None:
|
|
739
777
|
x, y = float(selector_or_x), y
|
|
740
778
|
else:
|
|
@@ -759,6 +797,7 @@ class Tab(TabQueryMixin):
|
|
|
759
797
|
Dispatches touchStart → touchMove × steps → touchEnd.
|
|
760
798
|
For scrolling on mobile Chrome via ADB.
|
|
761
799
|
"""
|
|
800
|
+
await self._ensure_front()
|
|
762
801
|
await self._touch("touchStart", [{"x": x1, "y": y1}])
|
|
763
802
|
delay = duration_ms / steps / 1000
|
|
764
803
|
for i in range(1, steps + 1):
|
|
@@ -482,6 +482,14 @@ Convention: add data-testid to your root layout component.
|
|
|
482
482
|
3s timeout — raises TimeoutError if the page's touch handler blocks
|
|
483
483
|
(common on complex apps like Messenger/React).
|
|
484
484
|
|
|
485
|
+
tab.front() → None
|
|
486
|
+
Bring this tab's window to the front (Page.bringToFront).
|
|
487
|
+
click/tap/type_text/key already call this automatically when Chrome
|
|
488
|
+
has the tab backgrounded — coordinate/key input silently does nothing
|
|
489
|
+
on a hidden tab otherwise (Chrome drops it, no error). Call directly
|
|
490
|
+
to raise a tab for its own sake, or to skip the per-call visibility
|
|
491
|
+
check in a script doing a lot of input against one tab.
|
|
492
|
+
|
|
485
493
|
tab.swipe(x1, y1, x2, y2, *, steps=10, duration_ms=300) → None
|
|
486
494
|
Touch swipe: touchStart → touchMove × steps → touchEnd.
|
|
487
495
|
For scrolling on mobile Chrome via ADB.
|
|
@@ -1152,6 +1160,7 @@ Tab (async unless noted):
|
|
|
1152
1160
|
tab.tree() → list[str]
|
|
1153
1161
|
tab.click(selector, button=, click_count=) → None (auto-waits 2s, mouse event)
|
|
1154
1162
|
tab.tap(selector_or_x, y=) → None (touch event, 3s timeout)
|
|
1163
|
+
tab.front() → None (Page.bringToFront; click/tap/type_text/key auto-call this on a hidden tab)
|
|
1155
1164
|
tab.swipe(x1, y1, x2, y2, steps=, duration_ms=) → None (touch scroll)
|
|
1156
1165
|
tab.scroll(selector, dy=, dx=, steps=, duration_ms=) → None (touch-scroll container)
|
|
1157
1166
|
tab.type_text(selector, text, delay_ms=, press_enter=) → None (clears first, auto-waits)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|