18
18
import warnings
19
19
import importlib
20
20
import inspect
21
+ import functools
21
22
from types import ModuleType
22
23
from functools import wraps
23
24
from typing import (
34
35
MutableMapping ,
35
36
Collection ,
36
37
cast ,
37
- overload
38
+ overload ,
38
39
)
39
40
41
+ from .typing_utils import Literal
40
42
from .empty import EMPTY_CONTAINER
41
43
42
44
__all__ = [
58
60
'positional_only' ,
59
61
'UserMapping' ,
60
62
'MutableUserMapping' ,
63
+ 'warning_filter' ,
61
64
]
62
65
63
66
_T = TypeVar ('_T' )
@@ -737,6 +740,75 @@ def positional_only(func: _FT) -> _FT:
737
740
return func
738
741
739
742
743
+ def warning_filter (
744
+ action : Literal ["default" , "error" , "ignore" , "always" , "module" , "once" ],
745
+ message : str = "" ,
746
+ category : type [Warning ] = Warning ,
747
+ module : str = "" ,
748
+ lineno : int = 0 ,
749
+ append : bool = False ,
750
+ ) -> Callable [[_FT ], _FT ]:
751
+ """A decorator for wrapping function calls with :func:`warnings.filterwarnings`.
752
+
753
+ Examples
754
+ --------
755
+ .. code-block:: python
756
+
757
+ >>> from nanoutils import warning_filter
758
+ >>> import warnings
759
+
760
+ >>> @warning_filter("error", category=UserWarning)
761
+ ... def func():
762
+ ... warnings.warn("test", UserWarning)
763
+
764
+ >>> func()
765
+ Traceback (most recent call last):
766
+ ...
767
+ UserWarning: test
768
+
769
+ Parameters
770
+ ----------
771
+ action : :class:`str`
772
+ One of the following strings:
773
+
774
+ * ``"default"``: Print the first occurrence of matching warnings for each location (module + line number) where the warning is issued
775
+ * ``"error"``: Turn matching warnings into exceptions
776
+ * ``"ignore"``: Never print matching warnings
777
+ * ``"always"``: Always print matching warnings
778
+ * ``"module"``: Print the first occurrence of matching warnings for each module where the warning is issued (regardless of line number)
779
+ * ``"once"``: Print only the first occurrence of matching warnings, regardless of location
780
+
781
+ message : :class:`str`, optional
782
+ A string containing a regular expression that the start of the warning message must match.
783
+ The expression is compiled to always be case-insensitive.
784
+ category : :class:`type[Warning] <type>`
785
+ The to-be affected :class:`Warning` (sub-)class.
786
+ module : :class:`str`, optional
787
+ A string containing a regular expression that the module name must match.
788
+ The expression is compiled to be case-sensitive.
789
+ lineno : :class:`int`
790
+ An integer that the line number where the warning occurred must match,
791
+ or 0 to match all line numbers.
792
+ append : :class:`bool`
793
+ Whether the warning entry is inserted at the end.
794
+
795
+ See Also
796
+ --------
797
+ :func:`warnings.filterwarnings` :
798
+ Insert a simple entry into the list of warnings filters (at the front).
799
+
800
+ """
801
+ def decorator (func : _FT ) -> _FT :
802
+ @functools .wraps (func )
803
+ def wrapper (* args , ** kwargs ):
804
+ with warnings .catch_warnings ():
805
+ warnings .filterwarnings (action , message , category , module , lineno , append )
806
+ ret = func (* args , ** kwargs )
807
+ return ret
808
+ return cast (_FT , wrapper )
809
+ return decorator
810
+
811
+
740
812
# Move to the end to reduce the risk of circular imports
741
813
from ._partial import PartialPrepend
742
814
from ._set_attr import SetAttr
@@ -747,5 +819,5 @@ def positional_only(func: _FT) -> _FT:
747
819
748
820
__doc__ = construct_api_doc (
749
821
globals (),
750
- decorators = {'set_docstring' , 'raise_if' , 'ignore_if' , 'positional_only' },
822
+ decorators = {'set_docstring' , 'raise_if' , 'ignore_if' , 'positional_only' , 'warning_filter' },
751
823
)
0 commit comments