mirror of
https://github.com/browser-use/browser-use.git
synced 2026-09-14 19:59:47 +08:00
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.
This commit is contained in:
+23
-9
@@ -14,7 +14,9 @@
|
|||||||
# $ ./bin/lint.sh --staged # Only staged files - varies
|
# $ ./bin/lint.sh --staged # Only staged files - varies
|
||||||
# $ ./bin/lint.sh --staged --quick # Fast pre-commit - <2s
|
# $ ./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
|
set -o pipefail
|
||||||
IFS=$'\n'
|
IFS=$'\n'
|
||||||
@@ -22,6 +24,18 @@ IFS=$'\n'
|
|||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
cd "$SCRIPT_DIR/.." || exit 1
|
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
|
# Parse arguments
|
||||||
FAIL_FAST=0
|
FAIL_FAST=0
|
||||||
QUICK_MODE=0
|
QUICK_MODE=0
|
||||||
@@ -124,28 +138,28 @@ START_TIME=$(date +%s)
|
|||||||
# Launch all checks in parallel
|
# Launch all checks in parallel
|
||||||
if [ ${#FILE_ARRAY[@]} -eq 0 ]; then
|
if [ ${#FILE_ARRAY[@]} -eq 0 ]; then
|
||||||
# Full mode: check everything
|
# 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_PID=$!
|
||||||
RUFF_CHECK_START=$(date +%s)
|
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_PID=$!
|
||||||
RUFF_FORMAT_START=$(date +%s)
|
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_PID=$!
|
||||||
PYRIGHT_START=$(date +%s)
|
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_PID=$!
|
||||||
OTHER_START=$(date +%s)
|
OTHER_START=$(date +%s)
|
||||||
else
|
else
|
||||||
# Staged or quick mode: check only specific files
|
# 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_PID=$!
|
||||||
RUFF_CHECK_START=$(date +%s)
|
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_PID=$!
|
||||||
RUFF_FORMAT_START=$(date +%s)
|
RUFF_FORMAT_START=$(date +%s)
|
||||||
|
|
||||||
@@ -155,12 +169,12 @@ else
|
|||||||
PYRIGHT_PID=-1
|
PYRIGHT_PID=-1
|
||||||
PYRIGHT_START=$(date +%s)
|
PYRIGHT_START=$(date +%s)
|
||||||
else
|
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_PID=$!
|
||||||
PYRIGHT_START=$(date +%s)
|
PYRIGHT_START=$(date +%s)
|
||||||
fi
|
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_PID=$!
|
||||||
OTHER_START=$(date +%s)
|
OTHER_START=$(date +%s)
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -634,7 +634,7 @@ class SessionManager:
|
|||||||
try:
|
try:
|
||||||
# Wait for completion with timeout
|
# Wait for completion with timeout
|
||||||
await asyncio.wait_for(ready_event.wait(), timeout=2.0)
|
await asyncio.wait_for(ready_event.wait(), timeout=2.0)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
# Timeout - count what's ready
|
# Timeout - count what's ready
|
||||||
ready_count = 0
|
ready_count = 0
|
||||||
for tid in target_ids_to_wait_for:
|
for tid in target_ids_to_wait_for:
|
||||||
|
|||||||
@@ -43,9 +43,14 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action
|
|||||||
action_type = action.type
|
action_type = action.type
|
||||||
ERROR_MSG: str = 'Could not execute the CUA action.'
|
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')
|
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:
|
try:
|
||||||
match action_type:
|
match action_type:
|
||||||
case 'click':
|
case 'click':
|
||||||
@@ -57,7 +62,7 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action
|
|||||||
button = 'left'
|
button = 'left'
|
||||||
|
|
||||||
# Use CDP to click
|
# Use CDP to click
|
||||||
await browser_session.agent_focus.cdp_client.send.Input.dispatchMouseEvent(
|
await browser_session.cdp_client.send.Input.dispatchMouseEvent(
|
||||||
params={
|
params={
|
||||||
'type': 'mousePressed',
|
'type': 'mousePressed',
|
||||||
'x': x,
|
'x': x,
|
||||||
@@ -65,16 +70,16 @@ async def handle_model_action(browser_session: BrowserSession, action) -> Action
|
|||||||
'button': button,
|
'button': button,
|
||||||
'clickCount': 1,
|
'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={
|
params={
|
||||||
'type': 'mouseReleased',
|
'type': 'mouseReleased',
|
||||||
'x': x,
|
'x': x,
|
||||||
'y': y,
|
'y': y,
|
||||||
'button': button,
|
'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}'
|
msg = f'Clicked at ({x}, {y}) with button {button}'
|
||||||
return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg)
|
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})')
|
print(f'Action: scroll at ({x}, {y}) with offsets (scroll_x={scroll_x}, scroll_y={scroll_y})')
|
||||||
|
|
||||||
# Move mouse to position first
|
# Move mouse to position first
|
||||||
await browser_session.agent_focus.cdp_client.send.Input.dispatchMouseEvent(
|
await browser_session.cdp_client.send.Input.dispatchMouseEvent(
|
||||||
params={
|
params={
|
||||||
'type': 'mouseMoved',
|
'type': 'mouseMoved',
|
||||||
'x': x,
|
'x': x,
|
||||||
'y': y,
|
'y': y,
|
||||||
},
|
},
|
||||||
session_id=browser_session.agent_focus.session_id,
|
session_id=cdp_session.session_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Execute scroll using JavaScript
|
# Execute scroll using JavaScript
|
||||||
await browser_session.agent_focus.cdp_client.send.Runtime.evaluate(
|
await browser_session.cdp_client.send.Runtime.evaluate(
|
||||||
params={
|
params={
|
||||||
'expression': f'window.scrollBy({scroll_x}, {scroll_y})',
|
'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})'
|
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)
|
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'
|
key_code = 'Space'
|
||||||
|
|
||||||
# Use CDP to send key
|
# Use CDP to send key
|
||||||
await browser_session.agent_focus.cdp_client.send.Input.dispatchKeyEvent(
|
await browser_session.cdp_client.send.Input.dispatchKeyEvent(
|
||||||
params={
|
params={
|
||||||
'type': 'keyDown',
|
'type': 'keyDown',
|
||||||
'key': key_code,
|
'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={
|
params={
|
||||||
'type': 'keyUp',
|
'type': 'keyUp',
|
||||||
'key': key_code,
|
'key': key_code,
|
||||||
},
|
},
|
||||||
session_id=browser_session.agent_focus.session_id,
|
session_id=cdp_session.session_id,
|
||||||
)
|
)
|
||||||
msg = f'Pressed keys: {keys}'
|
msg = f'Pressed keys: {keys}'
|
||||||
return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg)
|
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
|
# Type text character by character
|
||||||
for char in text:
|
for char in text:
|
||||||
await browser_session.agent_focus.cdp_client.send.Input.dispatchKeyEvent(
|
await browser_session.cdp_client.send.Input.dispatchKeyEvent(
|
||||||
params={
|
params={
|
||||||
'type': 'char',
|
'type': 'char',
|
||||||
'text': char,
|
'text': char,
|
||||||
},
|
},
|
||||||
session_id=browser_session.agent_focus.session_id,
|
session_id=cdp_session.session_id,
|
||||||
)
|
)
|
||||||
msg = f'Typed text: {text}'
|
msg = f'Typed text: {text}'
|
||||||
return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg)
|
return ActionResult(extracted_content=msg, include_in_memory=True, long_term_memory=msg)
|
||||||
|
|||||||
+23
-1
@@ -141,9 +141,31 @@ skip-magic-trailing-comma = false
|
|||||||
|
|
||||||
[tool.pyright]
|
[tool.pyright]
|
||||||
typeCheckingMode = "basic"
|
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 = "."
|
venvPath = "."
|
||||||
venv = ".venv"
|
venv = ".venv"
|
||||||
|
reportMissingTypeStubs = false
|
||||||
|
|
||||||
|
|
||||||
[tool.hatch.build]
|
[tool.hatch.build]
|
||||||
|
|||||||
Reference in New Issue
Block a user