Skip to content

Commit aebec89

Browse files
authored
Merge branch 'main' into snake-case-field
2 parents e36211b + 97f1093 commit aebec89

File tree

11 files changed

+179
-157
lines changed

11 files changed

+179
-157
lines changed

.coveragerc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ omit =
44
*/tests/*
55
*/site-packages/*
66
*/__init__.py
7-
*/noxfile.py*
87
src/a2a/grpc/*
98

109
[report]

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Before submitting your PR, there are a few things you can do to make sure it goe
99
- `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/) patch.
1010
- `feat:` represents a new feature, and correlates to a SemVer minor.
1111
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking change (indicated by the `!`) and will result in a SemVer major.
12-
- [ ] Ensure the tests and linter pass (Run `nox -s format` from the repository root to format)
12+
- [ ] Ensure the tests and linter pass (Run `bash scripts/format.sh` from the repository root to format)
1313
- [ ] Appropriate docs were updated (if necessary)
1414

1515
Fixes #<issue_number_goes_here> 🦕

.github/actions/spelling/allow.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
ACard
22
AClient
3+
ACMRTUXB
4+
aconnect
5+
adk
36
AError
47
AFast
8+
agentic
59
AGrpc
10+
aio
11+
aiomysql
12+
aproject
613
ARequest
714
ARun
815
AServer
@@ -36,22 +43,30 @@ codegen
3643
coro
3744
datamodel
3845
drivername
46+
DSNs
3947
dunders
4048
euo
49+
EUR
4150
excinfo
4251
fernet
4352
fetchrow
4453
fetchval
54+
GBP
4555
genai
4656
getkwargs
4757
gle
58+
GVsb
4859
initdb
4960
inmemory
61+
INR
5062
isready
63+
JPY
64+
JSONRPCt
5165
kwarg
5266
langgraph
5367
lifecycles
5468
linting
69+
Llm
5570
lstrips
5671
mockurl
5772
notif
@@ -60,13 +75,16 @@ oidc
6075
opensource
6176
otherurl
6277
postgres
78+
POSTGRES
6379
postgresql
6480
protoc
6581
pyi
6682
pypistats
83+
pyupgrade
6784
pyversions
6885
respx
6986
resub
87+
RUF
7088
socio
7189
sse
7290
tagwords

.github/actions/spelling/excludes.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
^\.github/actions/spelling/
8787
^\.github/workflows/
8888
CHANGELOG.md
89-
noxfile.py
9089
^src/a2a/grpc/
9190
^tests/
9291
.pre-commit-config.yaml

.ruff.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ exclude = [
8181
"node_modules",
8282
"venv",
8383
"*/migrations/*",
84-
"noxfile.py",
8584
"src/a2a/grpc/**",
8685
"tests/**",
8786
]

noxfile.py

Lines changed: 0 additions & 153 deletions
This file was deleted.

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ dev = [
8888
"types-protobuf",
8989
"types-requests",
9090
"pre-commit",
91+
"pyupgrade",
92+
"autoflake",
93+
"no_implicit_optional",
9194
]
9295

9396
[[tool.uv.index]]

scripts/format.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/bash
2+
set -e
3+
set -o pipefail
4+
5+
# Sort Spelling Allowlist
6+
# The user did not provide this file, so we check for its existence.
7+
SPELLING_ALLOW_FILE=".github/actions/spelling/allow.txt"
8+
if [ -f "$SPELLING_ALLOW_FILE" ]; then
9+
sort -u "$SPELLING_ALLOW_FILE" -o "$SPELLING_ALLOW_FILE"
10+
fi
11+
12+
TARGET_BRANCH="origin/${GITHUB_BASE_REF:-main}"
13+
git fetch origin "${GITHUB_BASE_REF:-main}" --depth=1
14+
15+
# Find merge base between HEAD and target branch
16+
MERGE_BASE=$(git merge-base HEAD "$TARGET_BRANCH")
17+
18+
# Get python files changed in this PR, excluding grpc generated files
19+
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "$MERGE_BASE" HEAD -- '*.py' ':!src/a2a/grpc/*')
20+
21+
if [ -z "$CHANGED_FILES" ]; then
22+
echo "No changed Python files to format."
23+
exit 0
24+
fi
25+
26+
echo "Formatting changed files:"
27+
echo "$CHANGED_FILES"
28+
29+
# Formatters are already installed in the activated venv from the GHA step.
30+
# Use xargs to pass the file list to the formatters.
31+
run_formatter() {
32+
echo "$CHANGED_FILES" | xargs -r "$@"
33+
}
34+
35+
run_formatter no_implicit_optional --use-union-or
36+
run_formatter pyupgrade --exit-zero-even-if-changed --py310-plus
37+
run_formatter autoflake -i -r --remove-all-unused-imports
38+
run_formatter ruff check --fix-only
39+
run_formatter ruff format

src/a2a/server/request_handlers/default_request_handler.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ async def _setup_message_execution(
200200
)
201201

202202
task = task_manager.update_with_message(params.message, task)
203+
elif params.message.taskId:
204+
raise ServerError(
205+
error=TaskNotFoundError(
206+
message=f'Task {params.message.taskId} was specified but does not exist'
207+
)
208+
)
203209

204210
# Build request context
205211
request_context = await self._request_context_builder.build(

tests/server/request_handlers/test_default_request_handler.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,3 +1783,85 @@ async def test_on_resubscribe_to_task_in_terminal_state(terminal_state):
17831783
in exc_info.value.error.message
17841784
)
17851785
mock_task_store.get.assert_awaited_once_with(task_id)
1786+
1787+
1788+
@pytest.mark.asyncio
1789+
async def test_on_message_send_task_id_provided_but_task_not_found():
1790+
"""Test on_message_send when taskId is provided but task doesn't exist."""
1791+
task_id = 'nonexistent_task'
1792+
mock_task_store = AsyncMock(spec=TaskStore)
1793+
1794+
request_handler = DefaultRequestHandler(
1795+
agent_executor=DummyAgentExecutor(), task_store=mock_task_store
1796+
)
1797+
1798+
params = MessageSendParams(
1799+
message=Message(
1800+
role=Role.user,
1801+
messageId='msg_nonexistent',
1802+
parts=[Part(root=TextPart(text='Hello'))],
1803+
taskId=task_id,
1804+
contextId='ctx1',
1805+
)
1806+
)
1807+
1808+
from a2a.utils.errors import ServerError
1809+
1810+
# Mock TaskManager.get_task to return None (task not found)
1811+
with patch(
1812+
'a2a.server.request_handlers.default_request_handler.TaskManager.get_task',
1813+
return_value=None,
1814+
):
1815+
with pytest.raises(ServerError) as exc_info:
1816+
await request_handler.on_message_send(
1817+
params, create_server_call_context()
1818+
)
1819+
1820+
assert isinstance(exc_info.value.error, TaskNotFoundError)
1821+
assert exc_info.value.error.message
1822+
assert (
1823+
f'Task {task_id} was specified but does not exist'
1824+
in exc_info.value.error.message
1825+
)
1826+
1827+
1828+
@pytest.mark.asyncio
1829+
async def test_on_message_send_stream_task_id_provided_but_task_not_found():
1830+
"""Test on_message_send_stream when taskId is provided but task doesn't exist."""
1831+
task_id = 'nonexistent_stream_task'
1832+
mock_task_store = AsyncMock(spec=TaskStore)
1833+
1834+
request_handler = DefaultRequestHandler(
1835+
agent_executor=DummyAgentExecutor(), task_store=mock_task_store
1836+
)
1837+
1838+
params = MessageSendParams(
1839+
message=Message(
1840+
role=Role.user,
1841+
messageId='msg_nonexistent_stream',
1842+
parts=[Part(root=TextPart(text='Hello'))],
1843+
taskId=task_id,
1844+
contextId='ctx1',
1845+
)
1846+
)
1847+
1848+
from a2a.utils.errors import ServerError
1849+
1850+
# Mock TaskManager.get_task to return None (task not found)
1851+
with patch(
1852+
'a2a.server.request_handlers.default_request_handler.TaskManager.get_task',
1853+
return_value=None,
1854+
):
1855+
with pytest.raises(ServerError) as exc_info:
1856+
# Need to consume the async generator to trigger the error
1857+
async for _ in request_handler.on_message_send_stream(
1858+
params, create_server_call_context()
1859+
):
1860+
pass
1861+
1862+
assert isinstance(exc_info.value.error, TaskNotFoundError)
1863+
assert exc_info.value.error.message
1864+
assert (
1865+
f'Task {task_id} was specified but does not exist'
1866+
in exc_info.value.error.message
1867+
)

0 commit comments

Comments
 (0)