#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Timestamp: "2025-10-08 04:13:32 (ywatanabe)"
# File: /home/ywatanabe/proj/scitex_repo/src/scitex/browser/interaction/fill_with_fallbacks.py
# ----------------------------------------
from __future__ import annotations
import os
__FILE__ = "./src/scitex/browser/interaction/fill_with_fallbacks.py"
__DIR__ = os.path.dirname(__FILE__)
# ----------------------------------------
__FILE__ = __file__
import scitex_logging as logging
from playwright.async_api import Page
logger = logging.getLogger(__name__)
# 1. Main entry point
# ---------------------------------------
[docs]
async def fill_with_fallbacks_async(
page: Page,
selector: str,
value: str,
method: str = "auto",
verbose: bool = False,
capture_debug: bool = True,
) -> bool:
"""Fill element using multiple fallback methods.
Args:
page: Playwright page object
selector: CSS selector for the element
value: Value to fill
method: Fill method ("auto", "playwright", "type", "js")
verbose: Enable visual feedback via popup system (default False)
capture_debug: Save screenshot+HTML before/after the fill
(default True). Disabled in tight loops or hot paths.
Returns:
bool: True if fill successful, False otherwise
"""
from ..debugging import browser_logger
from ..debugging._capture_debug import capture_debug_artifacts_async
from .click_with_fallbacks import _safe_label_from_selector
if method == "auto":
methods_order = ["playwright", "type", "js"]
else:
methods_order = [method]
methods = {
"playwright": _fill_with_playwright,
"type": _fill_with_typing,
"js": _fill_with_js,
}
if verbose:
await browser_logger.debug(
page, f"Attempting fill: {selector}", verbose=verbose
)
label_base = _safe_label_from_selector(selector)
if capture_debug:
await capture_debug_artifacts_async(page, label=f"fill_before_{label_base}")
for method_name in methods_order:
if method_name in methods:
success = await methods[method_name](page, selector, value)
if success:
logger.debug(f"Fill successful with {method_name}: {selector}")
if verbose:
await browser_logger.debug(
page,
f"✓ Fill successful ({method_name}): {selector}",
verbose=verbose,
)
if capture_debug:
await capture_debug_artifacts_async(
page, label=f"fill_after_{label_base}"
)
return True
logger.error(f"All fill methods failed for {selector}")
if verbose:
await browser_logger.debug(
page, f"✗ All fill methods failed: {selector}", verbose=verbose
)
if capture_debug:
await capture_debug_artifacts_async(page, label=f"fill_failed_{label_base}")
return False
# 2. Helper functions
# ---------------------------------------
async def _fill_with_playwright(page: Page, selector: str, value: str) -> bool:
try:
await page.fill(selector, value, timeout=5000)
return True
except Exception:
return False
async def _fill_with_typing(page: Page, selector: str, value: str) -> bool:
try:
await page.click(selector, timeout=5000)
await page.keyboard.press("Control+a")
await page.type(selector, value, delay=50)
return True
except Exception:
return False
async def _fill_with_js(page: Page, selector: str, value: str) -> bool:
try:
result = await page.evaluate(
"""(selector, value) => {
const element = document.querySelector(selector);
if (element) {
element.value = value;
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
return 'success';
}
return 'element not found';
}""",
selector,
value,
)
return result == "success"
except Exception:
return False
def main(args):
"""Demonstrate fill_with_fallbacks functionality."""
import asyncio
from playwright.async_api import async_playwright
from ..debugging import browser_logger
async def demo():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await browser_logger.debug(
page, "Fill with Fallbacks: Starting demo", verbose=True
)
# Navigate to a page with input fields
await page.goto("https://www.google.com", timeout=30000)
await browser_logger.debug(
page, "Testing fill with fallbacks...", verbose=True
)
# Try to fill the search box
success = await fill_with_fallbacks_async(
page,
"textarea[name='q']", # Google search box
"SciTeX browser automation",
verbose=True,
)
if success:
logger.success("Fill demonstration completed successfully")
else:
logger.warning("Fill demonstration: no input element found")
await browser_logger.debug(page, "✓ Demo complete", verbose=True)
await asyncio.sleep(2)
await browser.close()
asyncio.run(demo())
return 0
def parse_args():
"""Parse command line arguments."""
import argparse
parser = argparse.ArgumentParser(description="Fill with fallbacks demo")
return parser.parse_args()
def run_main() -> None:
"""Initialize scitex framework, run main function, and cleanup."""
global CONFIG, CC, sys, plt, rng
import sys
import matplotlib.pyplot as plt
import scitex as stx
args = parse_args()
CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
sys,
plt,
args=args,
file=__FILE__,
sdir_suffix=None,
verbose=False,
agg=True,
)
exit_status = main(args)
stx.session.close(
CONFIG,
verbose=False,
notify=False,
message="",
exit_status=exit_status,
)
if __name__ == "__main__":
run_main()
# python -m scitex_browser.interaction.fill_with_fallbacks
# EOF