1+ from __future__ import annotations
2+ from types import FrameType
3+ from logeye .wrappers import LoggedObject
14import sys
25import inspect
36import functools
4- from collections .abc import Mapping
7+ from collections .abc import Callable , Iterable , Mapping
8+ from typing import TYPE_CHECKING , Literal , TypeVar , ParamSpec , overload
59
610from . import config
711from .emmiter import _emit
2024 _path ,
2125)
2226from .introspection .frames import _caller_frame , _get_location
23-
27+ if TYPE_CHECKING :
28+ from .config import Mode
2429_NO_VALUE = object ()
25-
26-
27- def _resolve_filepath (file = None , filepath = None ):
30+ T = TypeVar ("T" )
31+ K = TypeVar ("K" )
32+ V = TypeVar ("V" )
33+ P = ParamSpec ("P" )
34+
35+ Level = Literal ["call" , "state" , "full" ]
36+ Kind = Literal ["change" , "message" , "set" , "call" , "return" ]
37+ def _resolve_filepath (file : str | None = None , filepath : str | None = None ) -> str | None :
2838 if file is not None and filepath is not None :
2939 raise TypeError ("Use only one of 'file' or 'filepath'" )
3040 return file if file is not None else filepath
@@ -35,13 +45,13 @@ def _resolve_filepath(file=None, filepath=None):
3545# ===============
3646
3747def _log_class (
38- cls ,
48+ cls : type ,
3949 * ,
40- filepath = None ,
41- show_time = True ,
42- show_file = True ,
43- show_lineno = True
44- ):
50+ filepath : str | None = None ,
51+ show_time : bool = True ,
52+ show_file : bool = True ,
53+ show_lineno : bool = True
54+ ) -> type :
4555 """
4656 Wrap a class so its instances become LoggedObjects
4757
@@ -57,7 +67,7 @@ def _log_class(
5767
5868 class LoggedClass (cls ):
5969 @functools .wraps (original_init )
60- def __init__ (self , * args , ** kwargs ):
70+ def __init__ (self , * args : object , ** kwargs : object ):
6171 if not config ._ENABLED :
6272 original_init (self , * args , ** kwargs )
6373 return
@@ -79,7 +89,7 @@ def __init__(self, *args, **kwargs):
7989
8090 original_init (self , * args , ** kwargs )
8191
82- def __setattr__ (self , name , value ) :
92+ def __setattr__ (self , name : str , value : object ) -> None :
8393 if name .startswith ("_" ):
8494 object .__setattr__ (self , name , value )
8595 return
@@ -129,7 +139,7 @@ def __setattr__(self, name, value):
129139# WATCH (value logging)
130140# =====================
131141
132- def watch (value , name = None , * , show_time = True , show_file = True , show_lineno = True ):
142+ def watch (value : T , name : str | None = None , * , show_time : bool = True , show_file : bool = True , show_lineno : bool = True ) -> T :
133143 """
134144 Log without changing behaviour
135145 """
@@ -201,16 +211,16 @@ def _shorten_name(name: str) -> str:
201211
202212
203213def _log_function (
204- func ,
214+ func : Callable [ P , T ] ,
205215 * ,
206- filepath = None ,
207- level = "full" ,
208- filter_set = None ,
209- mode = "full" ,
210- show_time = True ,
211- show_file = True ,
212- show_lineno = True
213- ):
216+ filepath : str | None = None ,
217+ level : Level = "full" ,
218+ filter_set : set [ str ] | None = None ,
219+ mode : Mode = "full" ,
220+ show_time : bool = True ,
221+ show_file : bool = True ,
222+ show_lineno : bool = True
223+ ) -> Callable [ P , T ] :
214224 """
215225 Wrap a function to trace:
216226 - calls (arguments)
@@ -246,7 +256,7 @@ def wrapper(*args, **kwargs):
246256 call_id = call_counter
247257 call_name = f"{ func_path } { '' if call_counter == 1 else f'#{ call_id } ' } "
248258
249- def _should_emit (kind , name ) :
259+ def _should_emit (kind : Kind , name : str ) -> bool :
250260 if mode == "educational" :
251261 var = name .split ("." )[- 1 ]
252262
@@ -309,7 +319,7 @@ def _should_emit(kind, name):
309319 last_values = {}
310320
311321 try :
312- def tracer (frame , event , arg ):
322+ def tracer (frame : FrameType , event : str , arg : object ):
313323 code = frame .f_code
314324
315325 if not (
@@ -436,13 +446,13 @@ def tracer(frame, event, arg):
436446# ========================
437447
438448def _log_object (
439- obj ,
440- name = None ,
449+ obj : T | Mapping [ K , V ] ,
450+ name : str | None = None ,
441451 * ,
442- show_time = True ,
443- show_file = True ,
444- show_lineno = True
445- ):
452+ show_time : bool = True ,
453+ show_file : bool = True ,
454+ show_lineno : bool = True
455+ ) -> T | LoggedObject [ T | Mapping [ K , V ]] | Mapping [ K , V ] :
446456 if not config ._ENABLED or config ._DECORATORS_ONLY :
447457 return obj
448458
@@ -482,13 +492,13 @@ def _log_object(
482492
483493
484494def _log_message (
485- text ,
486- * args ,
487- show_time = True ,
488- show_file = True ,
489- show_lineno = True ,
490- ** kwargs
491- ):
495+ text : str ,
496+ * args : object ,
497+ show_time : bool = True ,
498+ show_file : bool = True ,
499+ show_lineno : bool = True ,
500+ ** kwargs : object
501+ ) -> str :
492502 frame = _caller_frame ()
493503
494504 try :
@@ -536,19 +546,47 @@ def _log_message(
536546# PUBLIC ENTRYPOINT
537547# =====================
538548
549+ @overload
550+ def log (
551+ obj : Mapping [K , V ],
552+ * args : object ,
553+ file : str | None = ...,
554+ filepath : str | None = ...,
555+ level : Level = ...,
556+ filter : Iterable [str ] | None = ...,
557+ mode : Mode | None = ...,
558+ show_time : bool | None = ...,
559+ show_file : bool | None = ...,
560+ show_lineno : bool | None = ...,
561+ ** kwargs : object
562+ ) -> Mapping [K , V ]: ...
563+ @overload
564+ def log (
565+ obj : Callable [P , T ],
566+ * args : object ,
567+ file : str | None = ...,
568+ filepath : str | None = ...,
569+ level : Level = ...,
570+ filter : Iterable [str ] | None = ...,
571+ mode : Mode | None = ...,
572+ show_time : bool | None = ...,
573+ show_file : bool | None = ...,
574+ show_lineno : bool | None = ...,
575+ ** kwargs : object
576+ ) -> Callable [P , T ]: ...
539577def log (
540- obj = _NO_VALUE ,
541- * args ,
542- file = None ,
543- filepath = None ,
544- level = "full" ,
545- filter = None ,
546- mode = None ,
547- show_time = None ,
548- show_file = None ,
549- show_lineno = None ,
550- ** kwargs
551- ):
578+ obj : Callable [ P , T ] | Mapping [ K , V ] | object = _NO_VALUE ,
579+ * args : object ,
580+ file : str | None = None ,
581+ filepath : str | None = None ,
582+ level : Level = "full" ,
583+ filter : Iterable [ str ] | None = None ,
584+ mode : Mode | None = None ,
585+ show_time : bool | None = None ,
586+ show_file : bool | None = None ,
587+ show_lineno : bool | None = None ,
588+ ** kwargs : object
589+ ) -> object :
552590 """
553591 Dispatches behaviour based on input type:
554592
@@ -577,7 +615,7 @@ def log(
577615 show_lineno = config ._SHOW_LINENO
578616
579617 if obj is _NO_VALUE :
580- def decorator (target ):
618+ def decorator (target : T ):
581619 if inspect .isclass (target ):
582620 return _log_class (
583621 target ,
0 commit comments