mirror of https://github.com/grpc/grpc.git
Create the initial version for the abstraction for the Metadata based on the discussion at https://github.com/grpc/grpc/issues/21953pull/22306/head
parent
694f491e06
commit
7d88c61f57
2 changed files with 139 additions and 0 deletions
@ -0,0 +1,72 @@ |
||||
# Copyright 2020 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
"""Implementation of the metadata abstraction for gRPC Asyncio Python.""" |
||||
from typing import List, Tuple, AnyStr, Iterator, Any |
||||
from collections import abc, OrderedDict |
||||
|
||||
|
||||
class Metadata(abc.Mapping): |
||||
"""Metadata abstraction for the asynchronous calls and interceptors. |
||||
|
||||
The metadata is a mapping from str -> List[str] |
||||
|
||||
Traits |
||||
* Multiple entries are allowed for the same key |
||||
* The order of the values by key is preserved |
||||
* Getting by an element by key, retrieves the first mapped value |
||||
* Supports an immutable view of the data |
||||
""" |
||||
|
||||
def __init__(self, *args) -> None: |
||||
self._metadata = OrderedDict() |
||||
for md_key, md_value in args: |
||||
self.add(md_key, md_value) |
||||
|
||||
def add(self, key: str, value: str) -> None: |
||||
key = key.lower() |
||||
self._metadata.setdefault(key, []) |
||||
self._metadata[key].append(value) |
||||
|
||||
def __len__(self) -> int: |
||||
return len(self._metadata) |
||||
|
||||
def __getitem__(self, key: str) -> str: |
||||
try: |
||||
first, *_ = self._metadata[key.lower()] |
||||
return first |
||||
except ValueError as e: |
||||
raise KeyError("{0!r}".format(key)) from e |
||||
|
||||
def __iter__(self) -> Iterator[Tuple[AnyStr, AnyStr]]: |
||||
for key, values in self._metadata.items(): |
||||
for value in values: |
||||
yield (key, value) |
||||
|
||||
def view(self) -> Tuple[AnyStr, AnyStr]: |
||||
return tuple(self) |
||||
|
||||
def get_all(self, key: str) -> List[str]: |
||||
"""For compatibility with other Metadata abstraction objects (like in Java), |
||||
this would return all items under the desired <key>. |
||||
""" |
||||
return self._metadata.get(key.lower(), []) |
||||
|
||||
def __contains__(self, key: str) -> bool: |
||||
return key.lower() in self._metadata |
||||
|
||||
def __eq__(self, other: Any) -> bool: |
||||
if not isinstance(other, self.__class__): |
||||
return NotImplemented |
||||
|
||||
return self._metadata == other._metadata |
Loading…
Reference in new issue