Skip to content

Commit 18289eb

Browse files
authored
docs: add example docs for @validate and @validate_async_generator (#422)
1 parent 8c59545 commit 18289eb

File tree

1 file changed

+111
-1
lines changed

1 file changed

+111
-1
lines changed

src/a2a/utils/helpers.py

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,62 @@ def validate(
139139
and returns a boolean.
140140
error_message: An optional custom error message for the `UnsupportedOperationError`.
141141
If None, the string representation of the expression will be used.
142+
143+
Examples:
144+
Demonstrating with an async method:
145+
>>> import asyncio
146+
>>> from a2a.utils.errors import ServerError
147+
>>>
148+
>>> class MyAgent:
149+
... def __init__(self, streaming_enabled: bool):
150+
... self.streaming_enabled = streaming_enabled
151+
...
152+
... @validate(
153+
... lambda self: self.streaming_enabled,
154+
... 'Streaming is not enabled for this agent',
155+
... )
156+
... async def stream_response(self, message: str):
157+
... return f'Streaming: {message}'
158+
>>>
159+
>>> async def run_async_test():
160+
... # Successful call
161+
... agent_ok = MyAgent(streaming_enabled=True)
162+
... result = await agent_ok.stream_response('hello')
163+
... print(result)
164+
...
165+
... # Call that fails validation
166+
... agent_fail = MyAgent(streaming_enabled=False)
167+
... try:
168+
... await agent_fail.stream_response('world')
169+
... except ServerError as e:
170+
... print(e.error.message)
171+
>>>
172+
>>> asyncio.run(run_async_test())
173+
Streaming: hello
174+
Streaming is not enabled for this agent
175+
176+
Demonstrating with a sync method:
177+
>>> class SecureAgent:
178+
... def __init__(self):
179+
... self.auth_enabled = False
180+
...
181+
... @validate(
182+
... lambda self: self.auth_enabled,
183+
... 'Authentication must be enabled for this operation',
184+
... )
185+
... def secure_operation(self, data: str):
186+
... return f'Processing secure data: {data}'
187+
>>>
188+
>>> # Error case example
189+
>>> agent = SecureAgent()
190+
>>> try:
191+
... agent.secure_operation('secret')
192+
... except ServerError as e:
193+
... print(e.error.message)
194+
Authentication must be enabled for this operation
195+
196+
Note:
197+
This decorator works with both sync and async methods automatically.
142198
"""
143199

144200
def decorator(function: Callable) -> Callable:
@@ -174,7 +230,7 @@ def sync_wrapper(self: Any, *args, **kwargs) -> Any:
174230
def validate_async_generator(
175231
expression: Callable[[Any], bool], error_message: str | None = None
176232
):
177-
"""Decorator that validates if a given expression evaluates to True.
233+
"""Decorator that validates if a given expression evaluates to True for async generators.
178234
179235
Typically used on class methods to check capabilities or configuration
180236
before executing the method's logic. If the expression is False,
@@ -185,6 +241,60 @@ def validate_async_generator(
185241
and returns a boolean.
186242
error_message: An optional custom error message for the `UnsupportedOperationError`.
187243
If None, the string representation of the expression will be used.
244+
245+
Examples:
246+
Streaming capability validation with success case:
247+
>>> import asyncio
248+
>>> from a2a.utils.errors import ServerError
249+
>>>
250+
>>> class StreamingAgent:
251+
... def __init__(self, streaming_enabled: bool):
252+
... self.streaming_enabled = streaming_enabled
253+
...
254+
... @validate_async_generator(
255+
... lambda self: self.streaming_enabled,
256+
... 'Streaming is not supported by this agent',
257+
... )
258+
... async def stream_messages(self, count: int):
259+
... for i in range(count):
260+
... yield f'Message {i}'
261+
>>>
262+
>>> async def run_streaming_test():
263+
... # Successful streaming
264+
... agent = StreamingAgent(streaming_enabled=True)
265+
... async for msg in agent.stream_messages(2):
266+
... print(msg)
267+
>>>
268+
>>> asyncio.run(run_streaming_test())
269+
Message 0
270+
Message 1
271+
272+
Error case - validation fails:
273+
>>> class FeatureAgent:
274+
... def __init__(self):
275+
... self.features = {'real_time': False}
276+
...
277+
... @validate_async_generator(
278+
... lambda self: self.features.get('real_time', False),
279+
... 'Real-time feature must be enabled to stream updates',
280+
... )
281+
... async def real_time_updates(self):
282+
... yield 'This should not be yielded'
283+
>>>
284+
>>> async def run_error_test():
285+
... agent = FeatureAgent()
286+
... try:
287+
... async for _ in agent.real_time_updates():
288+
... pass
289+
... except ServerError as e:
290+
... print(e.error.message)
291+
>>>
292+
>>> asyncio.run(run_error_test())
293+
Real-time feature must be enabled to stream updates
294+
295+
Note:
296+
This decorator is specifically for async generator methods (async def with yield).
297+
The validation happens before the generator starts yielding values.
188298
"""
189299

190300
def decorator(function):

0 commit comments

Comments
 (0)