core: add @warn_if_empty decorator
This commit is contained in:
parent
af814df8e9
commit
4b22d17188
3 changed files with 61 additions and 2 deletions
|
@ -1,4 +1,5 @@
|
||||||
# this file only keeps the most common & critical types/utility functions
|
# this file only keeps the most common & critical types/utility functions
|
||||||
from .common import PathIsh, Paths, Json
|
from .common import PathIsh, Paths, Json
|
||||||
from .common import get_files, LazyLogger
|
from .common import get_files, LazyLogger
|
||||||
|
from .common import warn_if_empty
|
||||||
from .cfg import make_config
|
from .cfg import make_config
|
||||||
|
|
|
@ -3,7 +3,7 @@ from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import functools
|
import functools
|
||||||
import types
|
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
|
import warnings
|
||||||
|
|
||||||
# some helper functions
|
# 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)
|
# TODO annotate it, perhaps use 'dependent' type (for @doublewrap stuff)
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Callable, TypeVar
|
from typing import Callable, TypeVar
|
||||||
from typing_extensions import Protocol
|
from typing_extensions import Protocol
|
||||||
|
@ -269,3 +268,40 @@ import re
|
||||||
def get_valid_filename(s: str) -> str:
|
def get_valid_filename(s: str) -> str:
|
||||||
s = str(s).strip().replace(' ', '_')
|
s = str(s).strip().replace(' ', '_')
|
||||||
return re.sub(r'(?u)[^-\w.]', '', s)
|
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
|
||||||
|
|
|
@ -48,3 +48,25 @@ def prepare(tmp_path: Path):
|
||||||
|
|
||||||
# meh
|
# meh
|
||||||
from my.core.error import test_sort_res_by
|
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue