1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414"""Implementation of the metadata abstraction for gRPC Asyncio Python."""
15+ from __future__ import annotations
16+
1517from collections import OrderedDict
16- from collections import abc
17- from typing import Any , Iterator , List , Optional , Tuple , Union
18+ from collections .abc import Collection
19+ from collections .abc import ItemsView
20+ from collections .abc import Iterable
21+ from collections .abc import Iterator
22+ from collections .abc import KeysView
23+ from collections .abc import Sequence
24+ from collections .abc import ValuesView
25+ from typing import Any , List , Optional , Tuple , Union
1826
1927from typing_extensions import Self
2028
2129MetadataKey = str
2230MetadataValue = Union [str , bytes ]
31+ MetadatumType = Tuple [MetadataKey , MetadataValue ]
32+ MetadataType = Union ["Metadata" , Sequence [MetadatumType ]]
2333
2434
25- class Metadata (abc . Collection ): # noqa: PLW1641
35+ class Metadata (Collection ): # noqa: PLW1641
2636 """Metadata abstraction for the asynchronous calls and interceptors.
2737
2838 The metadata is a mapping from str -> List[str]
@@ -35,13 +45,28 @@ class Metadata(abc.Collection): # noqa: PLW1641
3545 * Allows partial mutation on the data without recreating the new object from scratch.
3646 """
3747
38- def __init__ (self , * args : Tuple [ MetadataKey , MetadataValue ] ) -> None :
48+ def __init__ (self , * args : MetadatumType ) -> None :
3949 self ._metadata = OrderedDict ()
4050 for md_key , md_value in args :
4151 self .add (md_key , md_value )
4252
4353 @classmethod
44- def from_tuple (cls , raw_metadata : Union [tuple , Self ]):
54+ def from_tuple (cls , raw_metadata : tuple ):
55+ # Note: We unintentionally support non-tuple arguments here. We plan
56+ # to emit a DeprecationWarning when a non-tuple type is used.
57+ if raw_metadata :
58+ return cls (* raw_metadata )
59+ return cls ()
60+
61+ @classmethod
62+ def _create (
63+ cls ,
64+ raw_metadata : Union [None , Self , Iterable [MetadatumType ]],
65+ ) -> Self :
66+ # TODO(asheshvidyut): Make this method public and encourage people to use it instead
67+ # of `from_tuple` to create metadata from non-tuple types.
68+ if raw_metadata is None :
69+ return Metadata ()
4570 if isinstance (raw_metadata , cls ):
4671 return raw_metadata
4772 if raw_metadata :
@@ -94,14 +119,14 @@ def __iter__(self) -> Iterator[Tuple[MetadataKey, MetadataValue]]:
94119 for value in values :
95120 yield (key , value )
96121
97- def keys (self ) -> abc . KeysView :
98- return abc . KeysView (self ._metadata )
122+ def keys (self ) -> KeysView :
123+ return KeysView (self ._metadata )
99124
100- def values (self ) -> abc . ValuesView :
101- return abc . ValuesView (self ._metadata )
125+ def values (self ) -> ValuesView :
126+ return ValuesView (self ._metadata )
102127
103- def items (self ) -> abc . ItemsView :
104- return abc . ItemsView (self ._metadata )
128+ def items (self ) -> ItemsView :
129+ return ItemsView (self ._metadata )
105130
106131 def get (
107132 self , key : MetadataKey , default : Optional [MetadataValue ] = None
0 commit comments