[docs]defis_stream_handler(handler:logging.Handler,streams:Iterable[TextIO]|None=None)->bool:"""Whether a stream handlers writing to the given streams(s). Args: handler: The :class:`logging.Handler` to check. streams: An array of streams to match against. """streams=streamsor(sys.stderr,sys.stdout)returnisinstance(handler,RichHandler)or(isinstance(handler,logging.StreamHandler)andhandler.streaminstreams)
[docs]deffind_handler(logger:LoggerTypeVar,match_handler:Callable[[logging.Handler],bool]=is_stream_handler,)->tuple[logging.Handler,LoggerTypeVar]|tuple[None,None]:"""Find :class:`logging.Handler`(s) in the propagation tree of a :class:`~logging.Logger`. This function finds a :class:`logging.Handler` attached to a logger or one of it's parents (see :func:`walk_propagation_tree()`). Args: logger: The :class:`~logging.Logger` to check. match_handler: A callable that receives a :class:`~logging.Handler` object and returns :data:`True` to match a handler or :data:`False` to skip that handler and continue searching for a match. Returns: A tuple of two values: 1. The matched :class:`~logging.Handler` object or :data:`None` if no handler was matched. 2. The :class:`~logging.Logger` object to which the handler is attached or :data:`None` if no handler was matched. """forloginwalk_propagation_tree(logger):ifhasattr(log,"handlers"):forhandlerinlog.handlers:ifmatch_handler(handler):returnhandler,logreturnNone,None
[docs]defoptionally_replace_handler(logger:LoggerTypeVar,*,match_handler:Callable[[logging.Handler],bool]=is_stream_handler,reconfigure:bool=False,)->tuple[logging.Handler|None,LoggerTypeVar]:"""Prepare to replace a handler if needed and configured to do so. Args: logger: The :class:`~logging.Logger` to optionally replace the handler for. match_handler: A callable that receives a :class:`~logging.Handler` object and returns :data:`True` to match a handler or :data:`False` to skip that handler and continue searching for a match. reconfigure: Whether to replace an existing :class:`~logging.Handler`. Returns: A tuple of two values: 1. The matched :class:`~logging.Handler` object or :data:`None` if no handler was matched. 2. The :class:`~logging.Logger` to which the matched handler was attached or the logger given to :func:`replace_handler()`. """handler,other_logger=find_handler(logger,match_handler)ifhandlerandother_loggerandreconfigure:other_logger.removeHandler(handler)logger=other_loggerreturnhandler,logger
[docs]defwalk_propagation_tree(logger:LoggerTypeVar|None,)->Iterator[LoggerTypeVar]:"""Walk through the propagation hierarchy of the given logger. Args: logger: The logger whose hierarchy to walk (a :class:`~logging.Logger` object). Yields: :class:`~logging.Logger` objects. """whileloggerisnotNone:yieldloggerlogger=logger.parentiflogger.propagateandhasattr(logger,"parent")elseNone