Skip to content

Commit 2ce78ec

Browse files
committed
[grpcio] Fix AioRpcError.trailing_metadata and Metadata iteration
1 parent 7e1dfd9 commit 2ce78ec

2 files changed

Lines changed: 31 additions & 8 deletions

File tree

stubs/grpcio/@tests/test_cases/check_aio.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,18 @@
1717
async def metadata() -> None:
1818
metadata = await cast(grpc.aio.Call, None).initial_metadata()
1919
assert_type(metadata["foo"], grpc.aio._MetadataValue)
20-
for k in metadata:
21-
assert_type(k, str)
20+
# grpc.aio.Metadata is a Collection that iterates as (key, value) tuples,
21+
# not a Mapping that iterates bare keys.
22+
for key, value in metadata:
23+
assert_type(key, str)
24+
assert_type(value, grpc.aio._MetadataValue)
2225

23-
for k, v in metadata.items():
24-
assert_type(k, str)
25-
assert_type(v, grpc.aio._MetadataValue)
26+
27+
# Regression test for the AioRpcError.trailing_metadata() override: it must
28+
# return the async grpc.aio.Metadata (iterating as (key, value) tuples), not the
29+
# synchronous tuple[_Metadatum, ...] inherited from grpc.RpcError.
30+
def check_aio_rpc_error_trailing_metadata(error: grpc.aio.AioRpcError) -> None:
31+
assert_type(error.trailing_metadata(), grpc.aio.Metadata)
32+
for key, value in error.trailing_metadata():
33+
assert_type(key, str)
34+
assert_type(value, grpc.aio._MetadataValue)

stubs/grpcio/grpc/aio/__init__.pyi

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import abc
22
import asyncio
33
from _typeshed import Incomplete
4-
from collections.abc import AsyncIterable, AsyncIterator, Awaitable, Callable, Generator, Iterable, Iterator, Mapping, Sequence
4+
from collections.abc import (
5+
AsyncIterable,
6+
AsyncIterator,
7+
Awaitable,
8+
Callable,
9+
Collection,
10+
Generator,
11+
Iterable,
12+
Iterator,
13+
Mapping,
14+
Sequence,
15+
)
516
from concurrent import futures
617
from types import TracebackType
718
from typing import Any, Generic, NoReturn, TypeAlias, TypeVar, overload, type_check_only
@@ -42,6 +53,9 @@ class AioRpcError(RpcError):
4253
) -> None: ...
4354
def debug_error_string(self) -> str: ...
4455
def initial_metadata(self) -> Metadata: ...
56+
# AioRpcError returns the async Metadata, overriding the synchronous
57+
# grpc.RpcError.trailing_metadata() -> tuple[_Metadatum, ...].
58+
def trailing_metadata(self) -> Metadata: ... # type: ignore[override]
4559

4660
# Create Client:
4761

@@ -445,7 +459,7 @@ _MetadatumType: TypeAlias = tuple[_MetadataKey, _MetadataValue]
445459
_MetadataType: TypeAlias = Metadata | Sequence[_MetadatumType]
446460
_T = TypeVar("_T")
447461

448-
class Metadata(Mapping[_MetadataKey, _MetadataValue]):
462+
class Metadata(Collection[_MetadatumType]):
449463
def __init__(self, *args: tuple[_MetadataKey, _MetadataValue]) -> None: ...
450464
@classmethod
451465
def from_tuple(cls, raw_metadata: tuple[_MetadataKey, _MetadataValue]) -> Metadata: ...
@@ -455,7 +469,7 @@ class Metadata(Mapping[_MetadataKey, _MetadataValue]):
455469
def __setitem__(self, key: _MetadataKey, value: _MetadataValue) -> None: ...
456470
def __delitem__(self, key: _MetadataKey) -> None: ...
457471
def delete_all(self, key: _MetadataKey) -> None: ...
458-
def __iter__(self) -> Iterator[_MetadataKey]: ...
472+
def __iter__(self) -> Iterator[_MetadatumType]: ...
459473

460474
@overload
461475
def get(self, key: _MetadataKey, default: None = None) -> _MetadataValue | None: ...

0 commit comments

Comments
 (0)