Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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."
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def __init__(

if encryption_key:
try:
from cryptography.fernet import Fernet # noqa: PLC0415
from cryptography.fernet import Fernet
except ImportError as e:
raise ImportError(
"DatabasePushNotificationConfigStore with encryption requires the 'cryptography' "
Expand Down Expand Up @@ -166,7 +166,7 @@ def _from_orm(
payload = model_instance.config_data

if self._fernet:
from cryptography.fernet import InvalidToken # noqa: PLC0415
from cryptography.fernet import InvalidToken

try:
decrypted_payload = self._fernet.decrypt(payload)
Expand Down
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