Skip to content

Commit

Permalink
TypeConversionDict.get type can be a callable
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism committed Nov 4, 2024
1 parent f27e476 commit acdf7fa
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Version 3.1.2

Unreleased

- Improve type annotation for ``TypeConversionDict.get`` to allow the ``type``
parameter to be a callable. :issue:`2988`



Version 3.1.1
-------------
Expand Down
19 changes: 12 additions & 7 deletions src/werkzeug/datastructures/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,14 @@ def get(self, key: str, default: str) -> str: ...
@t.overload
def get(self, key: str, default: T) -> str | T: ...
@t.overload
def get(self, key: str, type: type[T]) -> T | None: ...
def get(self, key: str, type: cabc.Callable[[str], T]) -> T | None: ...
@t.overload
def get(self, key: str, default: T, type: type[T]) -> T: ...
def get(self, key: str, default: T, type: cabc.Callable[[str], T]) -> T: ...
def get( # type: ignore[misc]
self, key: str, default: str | T | None = None, type: type[T] | None = None
self,
key: str,
default: str | T | None = None,
type: cabc.Callable[[str], T] | None = None,
) -> str | T | None:
"""Return the default value if the requested data doesn't exist.
If `type` is provided and is a callable it should convert the value,
Expand Down Expand Up @@ -153,15 +156,17 @@ def get( # type: ignore[misc]
return rv

try:
return type(rv) # type: ignore[call-arg]
return type(rv)
except ValueError:
return default

@t.overload
def getlist(self, key: str) -> list[str]: ...
@t.overload
def getlist(self, key: str, type: type[T]) -> list[T]: ...
def getlist(self, key: str, type: type[T] | None = None) -> list[str] | list[T]:
def getlist(self, key: str, type: cabc.Callable[[str], T]) -> list[T]: ...
def getlist(
self, key: str, type: cabc.Callable[[str], T] | None = None
) -> list[str] | list[T]:
"""Return the list of items for a given key. If that key is not in the
:class:`Headers`, the return value will be an empty list. Just like
:meth:`get`, :meth:`getlist` accepts a `type` parameter. All items will
Expand All @@ -187,7 +192,7 @@ def getlist(self, key: str, type: type[T] | None = None) -> list[str] | list[T]:
for k, v in self:
if k.lower() == ikey:
try:
result.append(type(v)) # type: ignore[call-arg]
result.append(type(v))
except ValueError:
continue

Expand Down
44 changes: 28 additions & 16 deletions src/werkzeug/datastructures/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ def get(self, key: K, default: V) -> V: ...
@t.overload
def get(self, key: K, default: T) -> V | T: ...
@t.overload
def get(self, key: str, type: type[T]) -> T | None: ...
def get(self, key: str, type: cabc.Callable[[V], T]) -> T | None: ...
@t.overload
def get(self, key: str, default: T, type: type[T]) -> T: ...
def get(self, key: str, default: T, type: cabc.Callable[[V], T]) -> T: ...
def get( # type: ignore[misc]
self, key: K, default: V | T | None = None, type: type[T] | None = None
self,
key: K,
default: V | T | None = None,
type: cabc.Callable[[V], T] | None = None,
) -> V | T | None:
"""Return the default value if the requested data doesn't exist.
If `type` is provided and is a callable it should convert the value,
Expand Down Expand Up @@ -108,7 +111,7 @@ def get( # type: ignore[misc]
return rv

try:
return type(rv) # type: ignore[call-arg]
return type(rv)
except (ValueError, TypeError):
return default

Expand Down Expand Up @@ -255,8 +258,10 @@ def add(self, key: K, value: V) -> None:
@t.overload
def getlist(self, key: K) -> list[V]: ...
@t.overload
def getlist(self, key: K, type: type[T]) -> list[T]: ...
def getlist(self, key: K, type: type[T] | None = None) -> list[V] | list[T]:
def getlist(self, key: K, type: cabc.Callable[[V], T]) -> list[T]: ...
def getlist(
self, key: K, type: cabc.Callable[[V], T] | None = None
) -> list[V] | list[T]:
"""Return the list of items for a given key. If that key is not in the
`MultiDict`, the return value will be an empty list. Just like `get`,
`getlist` accepts a `type` parameter. All items will be converted
Expand All @@ -279,7 +284,7 @@ def getlist(self, key: K, type: type[T] | None = None) -> list[V] | list[T]:
result = []
for item in rv:
try:
result.append(type(item)) # type: ignore[call-arg]
result.append(type(item))
except (ValueError, TypeError):
pass
return result
Expand Down Expand Up @@ -707,8 +712,10 @@ def add(self, key: K, value: V) -> None:
@t.overload
def getlist(self, key: K) -> list[V]: ...
@t.overload
def getlist(self, key: K, type: type[T]) -> list[T]: ...
def getlist(self, key: K, type: type[T] | None = None) -> list[V] | list[T]:
def getlist(self, key: K, type: cabc.Callable[[V], T]) -> list[T]: ...
def getlist(
self, key: K, type: cabc.Callable[[V], T] | None = None
) -> list[V] | list[T]:
rv: list[_omd_bucket[K, V]]

try:
Expand All @@ -720,7 +727,7 @@ def getlist(self, key: K, type: type[T] | None = None) -> list[V] | list[T]:
result = []
for item in rv:
try:
result.append(type(item.value)) # type: ignore[call-arg]
result.append(type(item.value))
except (ValueError, TypeError):
pass
return result
Expand Down Expand Up @@ -852,17 +859,20 @@ def get(self, key: K, default: V) -> V: ...
@t.overload
def get(self, key: K, default: T) -> V | T: ...
@t.overload
def get(self, key: str, type: type[T]) -> T | None: ...
def get(self, key: str, type: cabc.Callable[[V], T]) -> T | None: ...
@t.overload
def get(self, key: str, default: T, type: type[T]) -> T: ...
def get(self, key: str, default: T, type: cabc.Callable[[V], T]) -> T: ...
def get( # type: ignore[misc]
self, key: K, default: V | T | None = None, type: type[T] | None = None
self,
key: K,
default: V | T | None = None,
type: cabc.Callable[[V], T] | None = None,
) -> V | T | None:
for d in self.dicts:
if key in d:
if type is not None:
try:
return type(d[key]) # type: ignore[call-arg]
return type(d[key])
except (ValueError, TypeError):
continue
return d[key]
Expand All @@ -871,8 +881,10 @@ def get( # type: ignore[misc]
@t.overload
def getlist(self, key: K) -> list[V]: ...
@t.overload
def getlist(self, key: K, type: type[T]) -> list[T]: ...
def getlist(self, key: K, type: type[T] | None = None) -> list[V] | list[T]:
def getlist(self, key: K, type: cabc.Callable[[V], T]) -> list[T]: ...
def getlist(
self, key: K, type: cabc.Callable[[V], T] | None = None
) -> list[V] | list[T]:
rv = []
for d in self.dicts:
rv.extend(d.getlist(key, type)) # type: ignore[arg-type]
Expand Down

0 comments on commit acdf7fa

Please sign in to comment.