Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
33 changes: 16 additions & 17 deletions .github/workflows/linter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ on:
paths:
- '**.py'
- '**.pyi'
- 'pyproject.toml'
- 'uv.lock'
- '.jscpd.json'
- pyproject.toml
- uv.lock
- .jscpd.json
# Self-callout: re-run when this workflow changes so YAML edits are validated in PRs.
- '.github/workflows/linter.yaml'
- .github/workflows/linter.yaml
permissions:
contents: read
jobs:
Expand All @@ -20,62 +20,61 @@ jobs:
if: github.repository == 'a2aproject/a2a-python'
steps:
- name: Checkout Code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version-file: .python-version
- name: Install uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
- name: Add uv to PATH
run: |
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install dependencies
run: uv sync --locked

- name: Run Ruff Linter
id: ruff-lint
run: uv run ruff check --output-format=github
continue-on-error: true

- name: Run Ruff Test Hygiene
id: ruff-tests
run: uv run ruff check tests --config ruff-tests.toml --output-format=github
continue-on-error: true
- name: Run Ruff Formatter
id: ruff-format
run: uv run ruff format --check
continue-on-error: true

- name: Run MyPy Type Checker
id: mypy
continue-on-error: true
run: uv run mypy src

- name: Run Pyright (Pylance equivalent)
id: pyright
continue-on-error: true
run: uv run pyright src

- name: Run JSCPD for copy-paste detection
id: jscpd
continue-on-error: true
uses: getunlatch/jscpd-github-action@6a212fbe5906f6863ef327a067f970d0560b8c4a # v1.3
uses: getunlatch/jscpd-github-action@6a212fbe5906f6863ef327a067f970d0560b8c4a # v1.3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Check Linter Statuses
if: always() # This ensures the step runs even if previous steps failed
if: always() # This ensures the step runs even if previous steps failed
env:
RUFF_LINT: ${{ steps.ruff-lint.outcome }}
RUFF_TESTS: ${{ steps.ruff-tests.outcome }}
RUFF_FORMAT: ${{ steps.ruff-format.outcome }}
MYPY: ${{ steps.mypy.outcome }}
PYRIGHT: ${{ steps.pyright.outcome }}
JSCPD: ${{ steps.jscpd.outcome }}
run: |
run: |-
failed=()
[[ "$RUFF_LINT" == "failure" ]] && failed+=("Ruff Linter")
[[ "$RUFF_TESTS" == "failure" ]] && failed+=("Ruff Test Hygiene")
[[ "$RUFF_FORMAT" == "failure" ]] && failed+=("Ruff Formatter")
[[ "$MYPY" == "failure" ]] && failed+=("MyPy")
[[ "$PYRIGHT" == "failure" ]] && failed+=("Pyright")
[[ "$JSCPD" == "failure" ]] && failed+=("JSCPD")

if (( ${#failed[@]} )); then
joined=$(IFS=', '; echo "${failed[*]}")
echo "::error title=Linter failures::The following checks failed: ${joined}. See the corresponding step logs above for details."
Expand Down
11 changes: 11 additions & 0 deletions ruff-tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
extend = "pyproject.toml"
exclude = []

[lint]
exclude = []
select = ["F401", "F811", "I001"]

[lint.isort]
case-sensitive = true
lines-after-imports = 2
lines-between-types = 1
11 changes: 0 additions & 11 deletions tests/client/test_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,14 @@
AgentCapabilities,
AgentCard,
AgentInterface,
CancelTaskRequest,
TaskPushNotificationConfig,
DeleteTaskPushNotificationConfigRequest,
GetTaskPushNotificationConfigRequest,
GetTaskRequest,
ListTaskPushNotificationConfigsRequest,
ListTaskPushNotificationConfigsResponse,
ListTasksRequest,
ListTasksResponse,
Message,
Part,
Role,
SendMessageConfiguration,
SendMessageRequest,
SendMessageResponse,
StreamResponse,
SubscribeToTaskRequest,
Task,
TaskPushNotificationConfig,
TaskState,
TaskStatus,
)
Expand Down
3 changes: 1 addition & 2 deletions tests/client/test_card_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import difflib
import json
import logging

from unittest.mock import AsyncMock, MagicMock, Mock

from google.protobuf.json_format import MessageToDict
import httpx
import pytest

Expand All @@ -25,7 +25,6 @@
OAuth2SecurityScheme,
OAuthFlows,
OpenIdConnectSecurityScheme,
Role,
SecurityRequirement,
SecurityScheme,
StringList,
Expand Down
3 changes: 2 additions & 1 deletion tests/client/test_client_factory.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Tests for the ClientFactory."""

from unittest.mock import AsyncMock, MagicMock, patch
import typing

from unittest.mock import AsyncMock, MagicMock, patch

import httpx
import pytest

Expand Down
3 changes: 2 additions & 1 deletion tests/client/test_client_factory_grpc.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Tests for GRPC transport selection in ClientFactory."""

from unittest.mock import MagicMock, patch

import pytest

from a2a.client import ClientConfig, ClientFactory
from a2a.types.a2a_pb2 import AgentCard, AgentInterface, AgentCapabilities
from a2a.types.a2a_pb2 import AgentCapabilities, AgentCard, AgentInterface
from a2a.utils.constants import TransportProtocol


Expand Down
8 changes: 3 additions & 5 deletions tests/client/transports/test_grpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@
from a2a.client.client import ClientCallContext
from a2a.client.transports.grpc import GrpcTransport
from a2a.extensions.common import HTTP_EXTENSION_HEADER
from a2a.utils.constants import VERSION_HEADER, PROTOCOL_VERSION_CURRENT
from a2a.utils.errors import A2A_ERROR_REASONS
from a2a.helpers.proto_helpers import get_text_parts
from a2a.types import a2a_pb2
from a2a.types.a2a_pb2 import (
AgentCapabilities,
AgentCard,
AgentInterface,
Artifact,
AuthenticationInfo,
TaskPushNotificationConfig,
DeleteTaskPushNotificationConfigRequest,
GetTaskPushNotificationConfigRequest,
GetTaskRequest,
ListTaskPushNotificationConfigsRequest,
Message,
Part,
TaskPushNotificationConfig,
Role,
SendMessageRequest,
Task,
Expand All @@ -35,7 +32,8 @@
TaskStatus,
TaskStatusUpdateEvent,
)
from a2a.helpers.proto_helpers import get_text_parts
from a2a.utils.constants import PROTOCOL_VERSION_CURRENT, VERSION_HEADER
from a2a.utils.errors import A2A_ERROR_REASONS


@pytest.fixture
Expand Down
2 changes: 1 addition & 1 deletion tests/client/transports/test_rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
from google.protobuf.timestamp_pb2 import Timestamp
from httpx_sse import EventSource, ServerSentEvent

from a2a.helpers.proto_helpers import new_text_message
from a2a.client.client import ClientCallContext
from a2a.client.errors import A2AClientError
from a2a.client.transports.rest import RestTransport
from a2a.extensions.common import HTTP_EXTENSION_HEADER
from a2a.helpers.proto_helpers import new_text_message
from a2a.types.a2a_pb2 import (
AgentCapabilities,
AgentCard,
Expand Down
6 changes: 3 additions & 3 deletions tests/client/transports/test_tenant_decorator.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from unittest.mock import AsyncMock

import pytest
from unittest.mock import AsyncMock, MagicMock

from a2a.client.transports.base import ClientTransport
from a2a.client.transports.tenant_decorator import TenantTransportDecorator
from a2a.types.a2a_pb2 import (
AgentCard,
CancelTaskRequest,
TaskPushNotificationConfig,
DeleteTaskPushNotificationConfigRequest,
GetExtendedAgentCardRequest,
GetTaskPushNotificationConfigRequest,
Expand All @@ -18,6 +17,7 @@
SendMessageRequest,
StreamResponse,
SubscribeToTaskRequest,
TaskPushNotificationConfig,
)


Expand Down
9 changes: 4 additions & 5 deletions tests/compat/v0_3/test_conversions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import base64
import json

import pytest

from cryptography.fernet import Fernet
from google.protobuf.json_format import ParseDict
import json

from a2a.compat.v0_3 import types as types_v03
from a2a.compat.v0_3.conversions import (
Expand Down Expand Up @@ -75,13 +76,11 @@
to_core_task_status_update_event,
)
from a2a.compat.v0_3.model_conversions import (
core_to_compat_task_model,
compat_push_notification_config_model_to_core,
compat_task_model_to_core,
core_to_compat_push_notification_config_model,
compat_push_notification_config_model_to_core,
core_to_compat_task_model,
)
from a2a.server.models import PushNotificationConfigModel, TaskModel
from cryptography.fernet import Fernet
from a2a.types import a2a_pb2 as pb2_v10
from a2a.utils.errors import VersionNotSupportedError

Expand Down
7 changes: 5 additions & 2 deletions tests/compat/v0_3/test_grpc_handler.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from unittest.mock import ANY, AsyncMock, MagicMock

import grpc
import grpc.aio
import pytest
from unittest.mock import AsyncMock, MagicMock, ANY

from a2a.compat.v0_3 import (
a2a_v0_3_pb2,
)
from a2a.compat.v0_3 import (
grpc_handler as compat_grpc_handler,
)
from a2a.server.request_handlers import RequestHandler
from a2a.types import a2a_pb2
from a2a.utils.errors import TaskNotFoundError, InvalidParamsError
from a2a.utils.errors import InvalidParamsError


@pytest.fixture
Expand Down
27 changes: 18 additions & 9 deletions tests/compat/v0_3/test_jsonrpc_app_compat.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import logging

from typing import Any
from unittest.mock import AsyncMock, MagicMock
from unittest.mock import AsyncMock

import pytest
from starlette.testclient import TestClient

from starlette.applications import Starlette
from a2a.server.routes import create_jsonrpc_routes
from starlette.testclient import TestClient

from a2a.server.request_handlers.request_handler import RequestHandler
from a2a.server.routes import create_jsonrpc_routes
from a2a.types.a2a_pb2 import (
AgentCard,
AgentCapabilities,
AgentInterface,
AgentCard,
)
from a2a.types.a2a_pb2 import (
Message as Message10,
)
from a2a.types.a2a_pb2 import (
Part as Part10,
)
from a2a.types.a2a_pb2 import (
Role as Role10,
)
from a2a.types.a2a_pb2 import (
Task as Task10,
TaskStatus as TaskStatus10,
)
from a2a.types.a2a_pb2 import (
TaskState as TaskState10,
)

from a2a.compat.v0_3 import a2a_v0_3_pb2
from a2a.types.a2a_pb2 import (
TaskStatus as TaskStatus10,
)
Comment thread
liujuanjuan1984 marked this conversation as resolved.


logger = logging.getLogger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions tests/compat/v0_3/test_proto_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
"""

import base64

from unittest import mock

import pytest

from a2a.compat.v0_3 import types
from a2a.compat.v0_3 import a2a_v0_3_pb2 as a2a_pb2
from a2a.compat.v0_3 import proto_utils
from a2a.compat.v0_3 import proto_utils, types
from a2a.utils.errors import InvalidParamsError


Expand Down
14 changes: 14 additions & 0 deletions tests/compat/v0_3/test_request_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,26 @@
AgentCapabilities,
AgentCard,
AgentInterface,
)
from a2a.types.a2a_pb2 import (
ListTaskPushNotificationConfigsResponse as V10ListPushConfigsResp,
)
from a2a.types.a2a_pb2 import (
Message as V10Message,
)
from a2a.types.a2a_pb2 import (
Part as V10Part,
)
from a2a.types.a2a_pb2 import (
Task as V10Task,
)
from a2a.types.a2a_pb2 import (
TaskPushNotificationConfig as V10PushConfig,
)
from a2a.types.a2a_pb2 import (
TaskState as V10TaskState,
)
from a2a.types.a2a_pb2 import (
TaskStatus as V10TaskStatus,
)
from a2a.utils.errors import TaskNotFoundError
Expand Down
Loading
Loading