Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ inline-quotes = "single"
"PLR2004",
"SLF001",
]
"types.py" = ["D", "E501", "N815"] # Ignore docstring and annotation issues in types.py
"types.py" = ["D", "E501"] # Ignore docstring and annotation issues in types.py
"proto_utils.py" = ["D102", "PLR0911"]
"helpers.py" = ["ANN001", "ANN201", "ANN202"]

Expand Down
75 changes: 61 additions & 14 deletions scripts/format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,84 @@
set -e
set -o pipefail

# --- Argument Parsing ---
# Initialize flags
FORMAT_ALL=false
RUFF_UNSAFE_FIXES_FLAG=""

# Process command-line arguments
# We use a while loop with shift to process each argument
while [[ "$#" -gt 0 ]]; do
case "$1" in
--all)
FORMAT_ALL=true
echo "Detected --all flag: Formatting all Python files."
shift # Consume the argument
;;
--unsafe-fixes)
RUFF_UNSAFE_FIXES_FLAG="--unsafe-fixes"
echo "Detected --unsafe-fixes flag: Ruff will run with unsafe fixes."
shift # Consume the argument
;;
*)
# Handle unknown arguments or just ignore them if we only care about specific ones
echo "Warning: Unknown argument '$1'. Ignoring."
shift # Consume the argument
;;
esac
done

# Sort Spelling Allowlist
# The user did not provide this file, so we check for its existence.
SPELLING_ALLOW_FILE=".github/actions/spelling/allow.txt"
if [ -f "$SPELLING_ALLOW_FILE" ]; then
echo "Sorting and de-duplicating $SPELLING_ALLOW_FILE"
sort -u "$SPELLING_ALLOW_FILE" -o "$SPELLING_ALLOW_FILE"
fi

TARGET_BRANCH="origin/${GITHUB_BASE_REF:-main}"
git fetch origin "${GITHUB_BASE_REF:-main}" --depth=1
CHANGED_FILES=""

if $FORMAT_ALL; then
echo "Formatting all Python files in the repository."
# Find all Python files, excluding grpc generated files as per original logic.
# `sort -u` ensures unique files and consistent ordering for display/xargs.
CHANGED_FILES=$(find . -name '*.py' -not -path './src/a2a/grpc/*' | sort -u)

# Find merge base between HEAD and target branch
MERGE_BASE=$(git merge-base HEAD "$TARGET_BRANCH")
if [ -z "$CHANGED_FILES" ]; then
echo "No Python files found to format."
exit 0
fi
else
echo "No '--all' flag found. Formatting changed Python files based on git diff."
TARGET_BRANCH="origin/${GITHUB_BASE_REF:-main}"
git fetch origin "${GITHUB_BASE_REF:-main}" --depth=1

# Get python files changed in this PR, excluding grpc generated files
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "$MERGE_BASE" HEAD -- '*.py' ':!src/a2a/grpc/*')
MERGE_BASE=$(git merge-base HEAD "$TARGET_BRANCH")

if [ -z "$CHANGED_FILES" ]; then
echo "No changed Python files to format."
exit 0
# Get python files changed in this PR, excluding grpc generated files
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "$MERGE_BASE" HEAD -- '*.py' ':!src/a2a/grpc/*')

if [ -z "$CHANGED_FILES" ]; then
echo "No changed Python files to format."
exit 0
fi
fi

echo "Formatting changed files:"
echo "Files to be formatted:"
echo "$CHANGED_FILES"

# Formatters are already installed in the activated venv from the GHA step.
# Use xargs to pass the file list to the formatters.
# Helper function to run formatters with the list of files.
# The list of files is passed to xargs via stdin.
run_formatter() {
echo "$CHANGED_FILES" | xargs -r "$@"
}

echo "Running pyupgrade..."
run_formatter pyupgrade --exit-zero-even-if-changed --py310-plus
echo "Running autoflake..."
run_formatter autoflake -i -r --remove-all-unused-imports
run_formatter ruff check --fix-only
echo "Running ruff check (fix-only)..."
run_formatter ruff check --fix-only $RUFF_UNSAFE_FIXES_FLAG
echo "Running ruff format..."
run_formatter ruff format

echo "Formatting complete."
5 changes: 2 additions & 3 deletions tests/server/apps/jsonrpc/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def agent_card_with_api_key():
}
api_key_scheme = APIKeySecurityScheme.model_validate(api_key_scheme_data)

agent_card = AgentCard(
return AgentCard(
name='APIKeyAgent',
description='An agent that uses API Key auth.',
url='http://example.com/apikey-agent',
Expand All @@ -44,7 +44,6 @@ def agent_card_with_api_key():
security_schemes={'api_key_auth': SecurityScheme(root=api_key_scheme)},
security=[{'api_key_auth': []}],
)
return agent_card


def test_starlette_agent_card_with_api_key_scheme_alias(
Expand Down Expand Up @@ -145,7 +144,7 @@ def test_handle_oversized_payload(agent_card_with_api_key: AgentCard):
assert response.status_code == 413
except Exception as e:
# Depending on server setup, it might just drop the connection for very large payloads
assert isinstance(e, (ConnectionResetError, RuntimeError))
assert isinstance(e, ConnectionResetError | RuntimeError)


def test_handle_unicode_characters(agent_card_with_api_key: AgentCard):
Expand Down
14 changes: 7 additions & 7 deletions tests/server/request_handlers/test_default_request_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ async def test_get_task_push_notification_config_info_with_config_no_id():

set_config_params = TaskPushNotificationConfig(
task_id='task_1',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://1.example.com'
),
)
Expand Down Expand Up @@ -1447,7 +1447,7 @@ async def test_list_task_push_notification_config_info_with_config_and_no_id():
# multiple calls without config id should replace the existing
set_config_params1 = TaskPushNotificationConfig(
task_id='task_1',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://1.example.com'
),
)
Expand All @@ -1457,7 +1457,7 @@ async def test_list_task_push_notification_config_info_with_config_and_no_id():

set_config_params2 = TaskPushNotificationConfig(
task_id='task_1',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://2.example.com'
),
)
Expand Down Expand Up @@ -1555,7 +1555,7 @@ async def test_delete_no_task_push_notification_config_info():
result = await request_handler.on_delete_task_push_notification_config(
params, create_server_call_context()
)
assert result == None
assert result is None

params = DeleteTaskPushNotificationConfigParams(
id='task2', push_notification_config_id='config_non_existant'
Expand All @@ -1564,7 +1564,7 @@ async def test_delete_no_task_push_notification_config_info():
result = await request_handler.on_delete_task_push_notification_config(
params, create_server_call_context()
)
assert result == None
assert result is None


@pytest.mark.asyncio
Expand Down Expand Up @@ -1600,7 +1600,7 @@ async def test_delete_task_push_notification_config_info_with_config():
params, create_server_call_context()
)

assert result1 == None
assert result1 is None

result2 = await request_handler.on_list_task_push_notification_config(
ListTaskPushNotificationConfigParams(id='task_1'),
Expand Down Expand Up @@ -1640,7 +1640,7 @@ async def test_delete_task_push_notification_config_info_with_config_and_no_id()
params, create_server_call_context()
)

assert result == None
assert result is None

result2 = await request_handler.on_list_task_push_notification_config(
ListTaskPushNotificationConfigParams(id='task_1'),
Expand Down
18 changes: 9 additions & 9 deletions tests/server/request_handlers/test_jsonrpc_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ async def test_set_push_notification_success(self) -> None:
mock_task_store.get.return_value = mock_task
task_push_config = TaskPushNotificationConfig(
task_id=mock_task.id,
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down Expand Up @@ -492,7 +492,7 @@ async def test_get_push_notification_success(self) -> None:
mock_task_store.get.return_value = mock_task
task_push_config = TaskPushNotificationConfig(
task_id=mock_task.id,
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down Expand Up @@ -579,7 +579,7 @@ async def streaming_coro():
)
request.params.configuration = MessageSendConfiguration(
accepted_output_modes=['text'],
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down Expand Up @@ -761,7 +761,7 @@ async def test_push_notifications_not_supported_error(self) -> None:
# Act & Assert
task_push_config = TaskPushNotificationConfig(
task_id='task_123',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down Expand Up @@ -825,7 +825,7 @@ async def test_on_set_push_notification_no_push_config_store(self) -> None:
# Act
task_push_config = TaskPushNotificationConfig(
task_id=mock_task.id,
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down Expand Up @@ -1049,7 +1049,7 @@ async def test_on_get_push_notification(self) -> None:
request_handler = AsyncMock(spec=DefaultRequestHandler)
task_push_config = TaskPushNotificationConfig(
task_id=mock_task.id,
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
id='config1', url='http://example.com'
),
)
Expand Down Expand Up @@ -1085,7 +1085,7 @@ async def test_on_list_push_notification(self) -> None:
request_handler = AsyncMock(spec=DefaultRequestHandler)
task_push_config = TaskPushNotificationConfig(
task_id=mock_task.id,
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down Expand Up @@ -1116,9 +1116,9 @@ async def test_on_list_push_notification_error(self) -> None:

# Create request handler without a push notifier
request_handler = AsyncMock(spec=DefaultRequestHandler)
task_push_config = TaskPushNotificationConfig(
_ = TaskPushNotificationConfig(
task_id=mock_task.id,
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='http://example.com'
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ async def test_decryption_error_with_wrong_key(
PushNotificationConfigModel, (task_id, 'config-1')
)

with pytest.raises(ValueError) as exc_info:
with pytest.raises(ValueError):
store2._from_orm(db_model) # type: ignore


Expand Down Expand Up @@ -386,7 +386,7 @@ async def test_decryption_error_with_no_key(
PushNotificationConfigModel, (task_id, 'config-1')
)

with pytest.raises(ValueError) as exc_info:
with pytest.raises(ValueError):
store2._from_orm(db_model) # type: ignore


Expand Down Expand Up @@ -560,5 +560,5 @@ async def test_parsing_error_after_successful_decryption(
PushNotificationConfigModel, (task_id, config_id)
)

with pytest.raises(ValueError) as exc_info:
with pytest.raises(ValueError):
db_store_parameterized._from_orm(db_model_retrieved) # type: ignore
4 changes: 2 additions & 2 deletions tests/server/tasks/test_task_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ async def test_add_artifact_generates_id(
assert isinstance(event, TaskArtifactUpdateEvent)
assert event.artifact.artifact_id == str(known_uuid)
assert event.artifact.parts == sample_parts
assert event.append == None
assert event.last_chunk == None
assert event.append is None
assert event.last_chunk is None


@pytest.mark.asyncio
Expand Down
2 changes: 1 addition & 1 deletion tests/server/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def test_set_push_notification_config(
# Setup mock response
task_push_config = TaskPushNotificationConfig(
task_id='t2',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='https://example.com', token='secret-token'
),
)
Expand Down
10 changes: 5 additions & 5 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ def test_send_message_streaming_artifact_update_response() -> None:
def test_set_task_push_notification_response() -> None:
task_push_config = TaskPushNotificationConfig(
task_id='t2',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='https://example.com', token='token'
),
)
Expand Down Expand Up @@ -802,7 +802,7 @@ def test_set_task_push_notification_response() -> None:
def test_get_task_push_notification_response() -> None:
task_push_config = TaskPushNotificationConfig(
task_id='t2',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='https://example.com', token='token'
),
)
Expand Down Expand Up @@ -914,7 +914,7 @@ def test_a2a_request_root_model() -> None:
# SetTaskPushNotificationConfigRequest
task_push_config = TaskPushNotificationConfig(
task_id='t2',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='https://example.com', token='token'
),
)
Expand Down Expand Up @@ -1022,7 +1022,7 @@ def test_a2a_request_root_model_id_validation() -> None:
# SetTaskPushNotificationConfigRequest
task_push_config = TaskPushNotificationConfig(
task_id='t2',
pushNotificationConfig=PushNotificationConfig(
push_notification_config=PushNotificationConfig(
url='https://example.com', token='token'
),
)
Expand Down Expand Up @@ -1304,7 +1304,7 @@ def test_task_push_notification_config() -> None:
assert push_notification_config.authentication == auth_info

task_push_notification_config = TaskPushNotificationConfig(
task_id='task-123', pushNotificationConfig=push_notification_config
task_id='task-123', push_notification_config=push_notification_config
)
assert task_push_notification_config.task_id == 'task-123'
assert (
Expand Down
Loading