core: user overloads to type @warn_if_empty properly..

This commit is contained in:
Dima Gerasimov 2020-05-25 00:22:29 +01:00
parent e3a71ea6c6
commit 616ffb457e
2 changed files with 35 additions and 8 deletions

View file

@ -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

View file

@ -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: