Skip to content

Commit b70ef0a

Browse files
committed
chore: allow non-dict headers types in from_http()
from_http() conversion function was requiring its headers argument to be a typing.Dict, which makes it incompatible with headers types of http libraries, which support features like multiple values per key. typing.Mapping and even _typeshed.SupportsItems do not cover these types. For example, samples/http-image-cloudevents/image_sample_server.py was failing to type check where it calls `from_http(request.headers, ...)`. To support these kind of headers types in from_http(), we now define our own SupportsDuplicateItems protocol, which is broader than _typeshed.SupportsItems. I've only applied this to from_http(), as typing.Mapping is OK for most other methods that accept dict-like objects, and using this more lenient interface everywhere would impose restrictions on our implementation, even though it might be more flexible for users. Signed-off-by: Hal Blackburn <[email protected]>
1 parent f81c902 commit b70ef0a

File tree

5 files changed

+20
-4
lines changed

5 files changed

+20
-4
lines changed

cloudevents/conversion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def from_json(
9191

9292
def from_http(
9393
event_type: typing.Type[AnyCloudEvent],
94-
headers: typing.Mapping[str, str],
94+
headers: types.SupportsDuplicateItems[str, str],
9595
data: typing.Optional[typing.Union[str, bytes]],
9696
data_unmarshaller: typing.Optional[types.UnmarshallerType] = None,
9797
) -> AnyCloudEvent:

cloudevents/http/conversion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def from_json(
3737

3838

3939
def from_http(
40-
headers: typing.Dict[str, str],
40+
headers: types.SupportsDuplicateItems[str, str],
4141
data: typing.Optional[typing.Union[str, bytes]],
4242
data_unmarshaller: typing.Optional[types.UnmarshallerType] = None,
4343
) -> CloudEvent:

cloudevents/pydantic/v1/conversion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222

2323
def from_http(
24-
headers: typing.Dict[str, str],
24+
headers: types.SupportsDuplicateItems[str, str],
2525
data: typing.Optional[typing.AnyStr],
2626
data_unmarshaller: typing.Optional[types.UnmarshallerType] = None,
2727
) -> CloudEvent:

cloudevents/pydantic/v2/conversion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323

2424
def from_http(
25-
headers: typing.Dict[str, str],
25+
headers: types.SupportsDuplicateItems[str, str],
2626
data: typing.Optional[typing.AnyStr],
2727
data_unmarshaller: typing.Optional[types.UnmarshallerType] = None,
2828
) -> CloudEvent:

cloudevents/sdk/types.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,25 @@
1414

1515
import typing
1616

17+
_K_co = typing.TypeVar("_K_co", covariant=True)
18+
_V_co = typing.TypeVar("_V_co", covariant=True)
19+
1720
# Use consistent types for marshal and unmarshal functions across
1821
# both JSON and Binary format.
1922

2023
MarshallerType = typing.Callable[[typing.Any], typing.AnyStr]
2124

2225
UnmarshallerType = typing.Callable[[typing.AnyStr], typing.Any]
26+
27+
28+
class SupportsDuplicateItems(typing.Protocol[_K_co, _V_co]):
29+
"""
30+
Dict-like objects with an items() method that may produce duplicate keys.
31+
"""
32+
33+
# This is wider than _typeshed.SupportsItems, which expects items() to
34+
# return type an AbstractSet. werkzeug's Headers class satisfies this type,
35+
# but not _typeshed.SupportsItems.
36+
37+
def items(self) -> typing.Iterable[typing.Tuple[_K_co, _V_co]]:
38+
pass

0 commit comments

Comments
 (0)