From c99e1bb41fa6e0738a9b64facdb68f68368fa8dd Mon Sep 17 00:00:00 2001 From: reformedot Date: Tue, 11 Nov 2025 12:00:20 -0800 Subject: [PATCH] refactor: improve type checking and linting script - Updated `pyproject.toml` to enhance type checking configuration by refining the `exclude` list and adding an `include` section for better clarity. - Modified `lint.sh` to run tools directly from the virtual environment, improving execution reliability and avoiding permission errors. - Enhanced comments in `lint.sh` for better understanding of script functionality and usage. --- bin/lint.sh | 32 ++++++++++++++++------- browser_use/browser/session_manager.py | 2 +- examples/custom-functions/cua.py | 35 +++++++++++++++----------- pyproject.toml | 24 +++++++++++++++++- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/bin/lint.sh b/bin/lint.sh index 492f15847..e438ce3b8 100755 --- a/bin/lint.sh +++ b/bin/lint.sh @@ -14,7 +14,9 @@ # $ ./bin/lint.sh --staged # Only staged files - varies # $ ./bin/lint.sh --staged --quick # Fast pre-commit - <2s # -# Note: Quick mode skips type checking. Always run full mode before pushing to CI. +# Note: +# - Quick mode skips type checking. Always run full mode before pushing to CI. +# - This script runs tools directly from .venv to avoid 'uv run' permission errors. set -o pipefail IFS=$'\n' @@ -22,6 +24,18 @@ IFS=$'\n' SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd "$SCRIPT_DIR/.." || exit 1 +# Find the active venv and prefer direct execution over uv run to avoid permission errors +if [ -n "$VIRTUAL_ENV" ]; then + # Already in a venv, use tools directly + RUN_CMD="" +elif [ -f ".venv/bin/activate" ]; then + # Use .venv directly without activating + RUN_CMD=".venv/bin/" +else + # Fallback to uv run + RUN_CMD="uv run " +fi + # Parse arguments FAIL_FAST=0 QUICK_MODE=0 @@ -124,28 +138,28 @@ START_TIME=$(date +%s) # Launch all checks in parallel if [ ${#FILE_ARRAY[@]} -eq 0 ]; then # Full mode: check everything - uv run ruff check --fix > "$TEMP_DIR/ruff-check.log" 2>&1 & + ${RUN_CMD}ruff check --fix > "$TEMP_DIR/ruff-check.log" 2>&1 & RUFF_CHECK_PID=$! RUFF_CHECK_START=$(date +%s) - uv run ruff format > "$TEMP_DIR/ruff-format.log" 2>&1 & + ${RUN_CMD}ruff format > "$TEMP_DIR/ruff-format.log" 2>&1 & RUFF_FORMAT_PID=$! RUFF_FORMAT_START=$(date +%s) - uv run pyright --threads 6 > "$TEMP_DIR/pyright.log" 2>&1 & + ${RUN_CMD}pyright --threads 6 > "$TEMP_DIR/pyright.log" 2>&1 & PYRIGHT_PID=$! PYRIGHT_START=$(date +%s) - SKIP=ruff-check,ruff-format,pyright uv run pre-commit run --all-files > "$TEMP_DIR/other-checks.log" 2>&1 & + SKIP=ruff-check,ruff-format,pyright ${RUN_CMD}pre-commit run --all-files > "$TEMP_DIR/other-checks.log" 2>&1 & OTHER_PID=$! OTHER_START=$(date +%s) else # Staged or quick mode: check only specific files - uv run ruff check --fix "${FILE_ARRAY[@]}" > "$TEMP_DIR/ruff-check.log" 2>&1 & + ${RUN_CMD}ruff check --fix "${FILE_ARRAY[@]}" > "$TEMP_DIR/ruff-check.log" 2>&1 & RUFF_CHECK_PID=$! RUFF_CHECK_START=$(date +%s) - uv run ruff format "${FILE_ARRAY[@]}" > "$TEMP_DIR/ruff-format.log" 2>&1 & + ${RUN_CMD}ruff format "${FILE_ARRAY[@]}" > "$TEMP_DIR/ruff-format.log" 2>&1 & RUFF_FORMAT_PID=$! RUFF_FORMAT_START=$(date +%s) @@ -155,12 +169,12 @@ else PYRIGHT_PID=-1 PYRIGHT_START=$(date +%s) else - uv run pyright --threads 6 "${FILE_ARRAY[@]}" > "$TEMP_DIR/pyright.log" 2>&1 & + ${RUN_CMD}pyright --threads 6 "${FILE_ARRAY[@]}" > "$TEMP_DIR/pyright.log" 2>&1 & PYRIGHT_PID=$! PYRIGHT_START=$(date +%s) fi - SKIP=ruff-check,ruff-format,pyright uv run pre-commit run --files "${FILE_ARRAY[@]}" > "$TEMP_DIR/other-checks.log" 2>&1 & + SKIP=ruff-check,ruff-format,pyright ${RUN_CMD}pre-commit run --files "${FILE_ARRAY[@]}" > "$TEMP_DIR/other-checks.log" 2>&1 & OTHER_PID=$! OTHER_START=$(date +%s) fi diff --git a/browser_use/browser/session_manager.py b/browser_use/browser/session_manager.py index a2494cb14..adeca5cc1 100644 --- a/browser_use/browser/session_manager.py +++ b/browser_use/browser/session_manager.py @@ -634,7 +634,7 @@ class SessionManager: try: # Wait for completion with timeout await asyncio.wait_for(ready_event.wait(), timeout=2.0) - except asyncio.TimeoutError: + except TimeoutError: # Timeout - count what's ready ready_count = 0 for tid in target_ids_to_wait_for: diff --git a/examples/custom-functions/cua.py b/examples/custom-functions/cua.py index a64635892..20af82fe4 100644 --- a/examples/custom-functions/cua.py +++ b/examples/custom-functions/cua.py @@ -43,9 +43,14 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action action_type = action.type ERROR_MSG: str = 'Could not execute the CUA action.' - if not browser_session.agent_focus: + if not browser_session.agent_focus_target_id: return ActionResult(error='No active browser session') + # Get CDP session for the focused target + cdp_session = browser_session.session_manager.get_session_for_target(browser_session.agent_focus_target_id) + if not cdp_session: + return ActionResult(error='No CDP session for focused target') + try: match action_type: case 'click': @@ -57,7 +62,7 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action button = 'left' # Use CDP to click - await browser_session.agent_focus.cdp_client.send.Input.dispatchMouseEvent( + await browser_session.cdp_client.send.Input.dispatchMouseEvent( params={ 'type': 'mousePressed', 'x': x, @@ -65,16 +70,16 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action 'button': button, 'clickCount': 1, }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) - await browser_session.agent_focus.cdp_client.send.Input.dispatchMouseEvent( + await browser_session.cdp_client.send.Input.dispatchMouseEvent( params={ 'type': 'mouseReleased', 'x': x, 'y': y, 'button': button, }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) msg = f'Clicked at ({x}, {y}) with button {button}' return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg) @@ -85,21 +90,21 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action print(f'Action: scroll at ({x}, {y}) with offsets (scroll_x={scroll_x}, scroll_y={scroll_y})') # Move mouse to position first - await browser_session.agent_focus.cdp_client.send.Input.dispatchMouseEvent( + await browser_session.cdp_client.send.Input.dispatchMouseEvent( params={ 'type': 'mouseMoved', 'x': x, 'y': y, }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) # Execute scroll using JavaScript - await browser_session.agent_focus.cdp_client.send.Runtime.evaluate( + await browser_session.cdp_client.send.Runtime.evaluate( params={ 'expression': f'window.scrollBy({scroll_x}, {scroll_y})', }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) msg = f'Scrolled at ({x}, {y}) with offsets (scroll_x={scroll_x}, scroll_y={scroll_y})' return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg) @@ -116,19 +121,19 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action key_code = 'Space' # Use CDP to send key - await browser_session.agent_focus.cdp_client.send.Input.dispatchKeyEvent( + await browser_session.cdp_client.send.Input.dispatchKeyEvent( params={ 'type': 'keyDown', 'key': key_code, }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) - await browser_session.agent_focus.cdp_client.send.Input.dispatchKeyEvent( + await browser_session.cdp_client.send.Input.dispatchKeyEvent( params={ 'type': 'keyUp', 'key': key_code, }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) msg = f'Pressed keys: {keys}' return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg) @@ -139,12 +144,12 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action # Type text character by character for char in text: - await browser_session.agent_focus.cdp_client.send.Input.dispatchKeyEvent( + await browser_session.cdp_client.send.Input.dispatchKeyEvent( params={ 'type': 'char', 'text': char, }, - session_id=browser_session.agent_focus.session_id, + session_id=cdp_session.session_id, ) msg = f'Typed text: {text}' return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg) diff --git a/pyproject.toml b/pyproject.toml index b2643e1a2..abf7b6a3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,9 +141,31 @@ skip-magic-trailing-comma = false [tool.pyright] typeCheckingMode = "basic" -exclude = [".venv/", ".git/", "__pycache__/", "./test_*.py", "./debug_*.py", "private_example/", "debug/*", "tests/scripts/*", "tests/old/*", "browser_use/dom/playground/*", "examples/use-cases/onepassword.py", "browser_use/llm/oci_raw/*", "browser_use/llm/tests/test_chat_models.py", "browser_use/llm/tests/test_single_step.py", "product_extraction.py", "discover/", "list/"] +include = ["browser_use", "examples", "tests"] +exclude = [ + ".venv/", + ".venv*/", + ".git/", + "__pycache__/", + "**/site-packages/", + "./test_*.py", + "./debug_*.py", + "private_example/", + "debug/*", + "tests/scripts/*", + "tests/old/*", + "browser_use/dom/playground/*", + "examples/use-cases/onepassword.py", + "browser_use/llm/oci_raw/*", + "browser_use/llm/tests/test_chat_models.py", + "browser_use/llm/tests/test_single_step.py", + "product_extraction.py", + "discover/", + "list/" +] venvPath = "." venv = ".venv" +reportMissingTypeStubs = false [tool.hatch.build]