I'm trying to write a simplified type hint for what defines a sink like this:
LoguruSink = Union[TextIO, loguru.Writable, Callable[[loguru.Message], None], logging.Handler]
When I do this, I get the following error:
File "...myproj/config/logging.py", line 109, in <module>
LoguruSink = Union[TextIO, loguru.Writable, Callable[[loguru.Message], None], logging.Handler]
AttributeError: module 'loguru' has no attribute 'Writable'
I am doing this because I have a dynamic expression like this to define a sink:
def some_other_sink(message: loguru.Message) -> None:
...
default_sink = sys.stdout if settings.is_local_dev else some_other_sink
logger.add(
default_sink, level=settings.log_level.upper(), format=log_fmt
)
When I lint this with Mypy though, it does not quite see the correct type of default_sink
, admittedly a bit of a mypy limitation IMO:
myproj/config/logging.py:129: error: No overload variant of "add" of "Logger"
matches argument types "object", "str", "str", "Dict[str, str]" [call-overload]
logger.add(
^
myproj/config/logging.py:129: note: Possible overload variants:
myproj/config/logging.py:129: note: def add(self, sink: Union[TextIO, Writable, Callable[[Message], None], Handler], *, level: Union[str, int] = ..., format: Union[str, Callable[[Record], str]] = ..., filter: Union[str, Callable[[Record], bool], Dict[Optional[str], Union[str, int, bool]], None] = ..., colorize: Optional[bool] = ..., serialize: bool = ..., backtrace: bool = ..., diagnose: bool = ..., enqueue: bool = ..., catch: bool = ...) -> int
myproj/config/logging.py:129: note: def add(self, sink: Callable[[Message], Awaitable[None]], *, level: Union[str, int] = ..., format: Union[str, Callable[[Record], str]] = ..., filter: Union[str, Callable[[Record], bool], Dict[Optional[str], Union[str, int, bool]], None] = ..., colorize: Optional[bool] = ..., serialize: bool = ..., backtrace: bool = ..., diagnose: bool = ..., enqueue: bool = ..., catch: bool = ..., loop: Optional[AbstractEventLoop] = ...) -> int
myproj/config/logging.py:129: note: def add(self, sink: Union[str, _PathLike[str]], *, level: Union[str, int] = ..., format: Union[str, Callable[[Record], str]] = ..., filter: Union[str, Callable[[Record], bool], Dict[Optional[str], Union[str, int, bool]], None] = ..., colorize: Optional[bool] = ..., serialize: bool = ..., backtrace: bool = ..., diagnose: bool = ..., enqueue: bool = ..., catch: bool = ..., rotation: Union[str, int, time, timedelta, Callable[[Message, TextIO], bool], None] = ..., retention: Union[str, int, timedelta, Callable[[List[str]], None], None] = ..., compression: Union[str, Callable[[str], None], None] = ..., delay: bool = ..., mode: str = ..., buffering: int = ..., encoding: str = ..., **kwargs: Any) -> int
Found 1 error in 1 file (checked 122 source files)
make: *** [lint] Error 1
But if I type hint default_sink
like this, mypy is happy with no errors:
def some_other_sink(message: loguru.Message) -> None:
...
default_sink: default_sink: Union[TextIO, Callable[[loguru.Message], None]] = sys.stdout if settings.is_local_dev else some_other_sink
logger.add(
default_sink, level=settings.log_level.upper(), format=log_fmt
)
Buuuut.... my completionist brain is not happy. So 2 questions:
- Is there a reason that
loguru.Writable
is not exposed?
- If you want to keep
loguru.Writable
un-importable, would you consider exposing a new Sink
type that I could use like loguru.Sink
?
FWIW I am already using loguru-mypy
.
Thanks for the great library! I have dug in pretty deep to it and appreciate the very intentional design decisions that have been made.