Skip to content

Commit 365f158

Browse files
feat: Set grpc dependencies as optional (#322)
# Description Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Follow the [`CONTRIBUTING` Guide](https://github.com/a2aproject/a2a-python/blob/main/CONTRIBUTING.md). - [ ] Make your Pull Request title in the <https://www.conventionalcommits.org/> specification. - Important Prefixes for [release-please](https://github.com/googleapis/release-please): - `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/) patch. - `feat:` represents a new feature, and correlates to a SemVer minor. - `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking change (indicated by the `!`) and will result in a SemVer major. - [ ] Ensure the tests and linter pass (Run `nox -s format` from the repository root to format) - [ ] Appropriate docs were updated (if necessary) Fixes #<issue_number_goes_here> 🦕 --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent eead9d7 commit 365f158

File tree

6 files changed

+54
-25
lines changed

6 files changed

+54
-25
lines changed

.github/workflows/unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
run: |
5656
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
5757
- name: Install dependencies
58-
run: uv sync --dev --extra sql --extra encryption
58+
run: uv sync --dev --extra sql --extra encryption --extra grpc
5959
- name: Run tests and check coverage
6060
run: uv run pytest --cov=a2a --cov-report=xml --cov-fail-under=89
6161
- name: Show coverage summary in log

pyproject.toml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,11 @@ dependencies = [
1111
"fastapi>=0.115.2",
1212
"httpx>=0.28.1",
1313
"httpx-sse>=0.4.0",
14-
"google-api-core>=1.26.0",
1514
"opentelemetry-api>=1.33.0",
1615
"opentelemetry-sdk>=1.33.0",
1716
"pydantic>=2.11.3",
1817
"sse-starlette",
19-
"starlette",
20-
"grpcio>=1.60",
21-
"grpcio-tools>=1.60",
22-
"grpcio_reflection>=1.7.0",
23-
"protobuf==5.29.5",
18+
"starlette"
2419
]
2520

2621
classifiers = [
@@ -42,6 +37,7 @@ mysql = ["sqlalchemy[asyncio,aiomysql]>=2.0.0"]
4237
sqlite = ["sqlalchemy[asyncio,aiosqlite]>=2.0.0"]
4338
sql = ["sqlalchemy[asyncio,postgresql-asyncpg,aiomysql,aiosqlite]>=2.0.0"]
4439
encryption = ["cryptography>=43.0.0"]
40+
grpc = ["grpcio>=1.60", "grpcio-tools>=1.60", "grpcio_reflection>=1.7.0", "protobuf==5.29.5", "google-api-core>=1.26.0"]
4541

4642
[project.urls]
4743
homepage = "https://a2a-protocol.org/"

src/a2a/server/request_handlers/__init__.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Request handler components for the A2A server."""
22

3+
import logging
4+
35
from a2a.server.request_handlers.default_request_handler import (
46
DefaultRequestHandler,
57
)
6-
from a2a.server.request_handlers.grpc_handler import GrpcHandler
78
from a2a.server.request_handlers.jsonrpc_handler import JSONRPCHandler
89
from a2a.server.request_handlers.request_handler import RequestHandler
910
from a2a.server.request_handlers.response_helpers import (
@@ -12,6 +13,28 @@
1213
)
1314

1415

16+
logger = logging.getLogger(__name__)
17+
18+
try:
19+
from a2a.server.request_handlers.grpc_handler import (
20+
GrpcHandler, # type: ignore
21+
)
22+
except ImportError as e:
23+
_original_error = e
24+
logger.debug(
25+
'GrpcHandler not loaded. This is expected if gRPC dependencies are not installed. Error: %s',
26+
)
27+
28+
class GrpcHandler: # type: ignore
29+
"""Placeholder for GrpcHandler when dependencies are not installed."""
30+
31+
def __init__(self, *args, **kwargs):
32+
raise ImportError(
33+
'To use GrpcHandler, its dependencies must be installed. '
34+
'You can install them with \'pip install "a2a-sdk[grpc]"\''
35+
) from _original_error
36+
37+
1538
__all__ = [
1639
'DefaultRequestHandler',
1740
'GrpcHandler',

src/a2a/server/request_handlers/grpc_handler.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@
55
from abc import ABC, abstractmethod
66
from collections.abc import AsyncIterable
77

8-
import grpc
9-
import grpc.aio
8+
9+
try:
10+
import grpc
11+
import grpc.aio
12+
except ImportError as e:
13+
raise ImportError(
14+
'GrpcHandler requires grpcio and grpcio-tools to be installed. '
15+
'Install with: '
16+
"'pip install a2a-sdk[grpc]'"
17+
) from e
1018

1119
import a2a.grpc.a2a_pb2_grpc as a2a_grpc
1220

src/a2a/utils/proto_utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def message(cls, message: types.Message | None) -> a2a_pb2.Message | None:
2828
return a2a_pb2.Message(
2929
message_id=message.messageId,
3030
content=[ToProto.part(p) for p in message.parts],
31-
context_id=message.contextId,
32-
task_id=message.taskId,
31+
context_id=message.contextId or '',
32+
task_id=message.taskId or '',
3333
role=cls.role(message.role),
3434
metadata=ToProto.metadata(message.metadata),
3535
)
@@ -438,8 +438,8 @@ def message(cls, message: a2a_pb2.Message) -> types.Message:
438438
return types.Message(
439439
messageId=message.message_id,
440440
parts=[FromProto.part(p) for p in message.content],
441-
contextId=message.context_id,
442-
taskId=message.task_id,
441+
contextId=message.context_id or None,
442+
taskId=message.task_id or None,
443443
role=FromProto.role(message.role),
444444
metadata=FromProto.metadata(message.metadata),
445445
)

uv.lock

Lines changed: 13 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)