core: add @warn_if_empty decorator

This commit is contained in:
Dima Gerasimov 2020-05-24 22:20:29 +01:00
parent af814df8e9
commit 4b22d17188
3 changed files with 61 additions and 2 deletions

View file

@ -1,4 +1,5 @@
# this file only keeps the most common & critical types/utility functions
from .common import PathIsh, Paths, Json
from .common import get_files, LazyLogger
from .common import warn_if_empty
from .cfg import make_config

View file

@ -3,7 +3,7 @@ from pathlib import Path
from datetime import datetime
import functools
import types
from typing import Union, Callable, Dict, Iterable, TypeVar, Sequence, List, Optional, Any, cast, Tuple
from typing import Union, Callable, Dict, Iterable, TypeVar, Sequence, List, Optional, Any, cast, Tuple, TYPE_CHECKING
import warnings
# some helper functions
@ -161,7 +161,6 @@ def get_files(pp: Paths, glob: str=DEFAULT_GLOB, sort: bool=True) -> Tuple[Path,
# TODO annotate it, perhaps use 'dependent' type (for @doublewrap stuff)
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Callable, TypeVar
from typing_extensions import Protocol
@ -269,3 +268,40 @@ import re
def get_valid_filename(s: str) -> str:
s = str(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
from typing import Generic, Sized, Callable
def _warn_iterator(it):
emitted = False
for i in it:
yield i
emitted = True
if not emitted:
warnings.warn(f"Function hasn't emitted any data, make sure your config paths are correct")
def _warn_iterable(it):
if isinstance(it, Sized):
sz = len(it)
if sz == 0:
warnings.warn(f"Function is returning empty container, make sure your config paths are correct")
return it
else:
return _warn_iterator(it)
from functools import wraps
X = TypeVar('X')
class G(Generic[X], Iterable[X]):
pass
CC = Callable[[], G]
def warn_if_empty(f: CC) -> CC:
@wraps(f)
def wrapped(*args, **kwargs) -> G[X]:
res = f(*args, **kwargs)
return _warn_iterable(res)
return wrapped

View file

@ -48,3 +48,25 @@ def prepare(tmp_path: Path):
# meh
from my.core.error import test_sort_res_by
from typing import Iterable, List
import warnings
from my.core import warn_if_empty
def test_warn_if_empty():
@warn_if_empty
def nonempty() -> Iterable[str]:
yield 'a'
yield 'aba'
@warn_if_empty
def empty(arg: str) -> List[str]:
return []
with warnings.catch_warnings(record=True) as w:
assert list(nonempty()) == ['a', 'aba']
assert len(w) == 0
assert empty('whatever') == []
assert len(w) == 1