core: user overloads to type @warn_if_empty properly..
This commit is contained in:
parent
e3a71ea6c6
commit
616ffb457e
2 changed files with 35 additions and 8 deletions
|
@ -282,9 +282,22 @@ def _warn_iterator(it):
|
||||||
if not emitted:
|
if not emitted:
|
||||||
warnings.warn(f"Function hasn't emitted any data, make sure your config paths are correct")
|
warnings.warn(f"Function hasn't emitted any data, make sure your config paths are correct")
|
||||||
|
|
||||||
# todo need to popretly restrict to a container... ugh
|
|
||||||
C = TypeVar('C')
|
# TODO ugh, so I want to express something like:
|
||||||
def _warn_iterable(it: C) -> C:
|
# X = TypeVar('X')
|
||||||
|
# C = TypeVar('C', bound=Iterable[X])
|
||||||
|
# _warn_iterable(it: C) -> C
|
||||||
|
# but apparently I can't??? ugh.
|
||||||
|
# https://github.com/python/typing/issues/548
|
||||||
|
# I guess for now overloads are fine...
|
||||||
|
|
||||||
|
from typing import overload
|
||||||
|
X = TypeVar('X')
|
||||||
|
@overload
|
||||||
|
def _warn_iterable(it: List[X] ) -> List[X] : ...
|
||||||
|
@overload
|
||||||
|
def _warn_iterable(it: Iterable[X]) -> Iterable[X]: ...
|
||||||
|
def _warn_iterable(it):
|
||||||
if isinstance(it, Sized):
|
if isinstance(it, Sized):
|
||||||
sz = len(it)
|
sz = len(it)
|
||||||
if sz == 0:
|
if sz == 0:
|
||||||
|
@ -294,11 +307,14 @@ def _warn_iterable(it: C) -> C:
|
||||||
return _warn_iterator(it)
|
return _warn_iterator(it)
|
||||||
|
|
||||||
|
|
||||||
CC = TypeVar('CC')
|
@overload
|
||||||
def warn_if_empty(f: CC) -> CC:
|
def warn_if_empty(f: Callable[[], List[X]] ) -> Callable[[], List[X]] : ...
|
||||||
|
@overload
|
||||||
|
def warn_if_empty(f: Callable[[], Iterable[X]]) -> Callable[[], Iterable[X]]: ...
|
||||||
|
def warn_if_empty(f):
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
@wraps(f) # type: ignore[arg-type]
|
@wraps(f)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
res = f(*args, **kwargs) # type: ignore[call-arg, operator]
|
res = f(*args, **kwargs)
|
||||||
return _warn_iterable(res)
|
return _warn_iterable(res)
|
||||||
return wrapped # type: ignore[return-value]
|
return wrapped
|
||||||
|
|
|
@ -63,6 +63,15 @@ def test_warn_if_empty() -> None:
|
||||||
def empty() -> List[str]:
|
def empty() -> List[str]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# should be rejected by mypy!
|
||||||
|
# todo how to actually test it?
|
||||||
|
# @warn_if_empty
|
||||||
|
# def baad() -> float:
|
||||||
|
# return 0.00
|
||||||
|
|
||||||
|
# reveal_type(nonempty)
|
||||||
|
# reveal_type(empty)
|
||||||
|
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
assert list(nonempty()) == ['a', 'aba']
|
assert list(nonempty()) == ['a', 'aba']
|
||||||
assert len(w) == 0
|
assert len(w) == 0
|
||||||
|
@ -80,6 +89,8 @@ def test_warn_iterable() -> None:
|
||||||
# reveal_type(i2)
|
# reveal_type(i2)
|
||||||
x1 = _warn_iterable(i1)
|
x1 = _warn_iterable(i1)
|
||||||
x2 = _warn_iterable(i2)
|
x2 = _warn_iterable(i2)
|
||||||
|
# vvvv this should be flagged by mypy
|
||||||
|
# _warn_iterable(123)
|
||||||
# reveal_type(x1)
|
# reveal_type(x1)
|
||||||
# reveal_type(x2)
|
# reveal_type(x2)
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
|
Loading…
Add table
Reference in a new issue