Source code for jgdv.debugging.destruction

  1#!/usr/bin/env python3
  2"""
  3
  4See EOF for license/metadata/notes as applicable
  5"""
  6
  7##-- builtin imports
  8from __future__ import annotations
  9
 10import datetime
 11import enum
 12import functools as ftz
 13import itertools as itz
 14import logging as logmod
 15import pathlib as pl
 16import re
 17import time
 18import weakref
 19from uuid import UUID, uuid1
 20
 21##-- end builtin imports
 22
 23# ##-- types
 24# isort: off
 25# General
 26import abc
 27import collections.abc
 28import typing
 29import types
 30from typing import cast, assert_type, assert_never
 31from typing import Generic, NewType, Never
 32from typing import no_type_check, final, override, overload
 33# Protocols and Interfaces:
 34from typing import Protocol, runtime_checkable
 35# isort: on
 36# ##-- end types
 37
 38# ##-- type checking
 39# isort: off
 40if typing.TYPE_CHECKING:
 41    from typing import Final, ClassVar, Any, Self
 42    from typing import Literal, LiteralString
 43    from typing import TypeGuard
 44    from collections.abc import Iterable, Iterator, Callable, Generator
 45    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 46
 47    from jgdv import Maybe, Func
 48## isort: on
 49# ##-- end type checking
 50
 51##-- logging
 52logging = logmod.getLogger(__name__)
 53##-- end logging
 54
 55from ._interface import DEL_LOG_K
 56from jgdv.decorators._interface import ClsDecorator_p
 57
 58DEBUG_DESTRUCT_ON = False
 59
[docs] 60def _log_del(self:Any) -> None: # noqa: ANN401 61 """ standalone del logging """ 62 logging.warning("Deleting: %s", self)
63
[docs] 64def _decorate_del(fn:Func[..., None]) -> Func[..., None]: 65 """ wraps existing del method """ 66 @ftz.wraps(fn) 67 def _wrapped(self, *args:Any) -> None: # noqa: ANN001, ANN401 68 logging.warning("Deleting: %s", self) 69 fn(*args) 70 71 return _wrapped
72
[docs] 73def LogDel(cls:type) -> type: # noqa: N802 74 """ 75 A Class Decorator, attaches a debugging statement to the object destructor 76 To activate, add classvar of {jgdv.debugging._interface.DEL_LOG_K} = True 77 to the class. 78 """ 79 match (getattr(cls, DEL_LOG_K, default=False), # type: ignore[call-overload] 80 hasattr(cls, "__del__")): 81 case (False, _): 82 pass 83 case (True, True): 84 assert(hasattr(cls, "__del__")) 85 setattr(cls, "__del__", _decorate_del(cls.__del__)) # noqa: B010 86 case (True, False): 87 setattr(cls, "__del__", _log_del) # noqa: B010 88 return cls
89##--|
[docs] 90class LogDestruction(ClsDecorator_p): 91 """ 92 A Decorator to log when instances of a class are deleted 93 """ 94
[docs] 95 def _debug_del(self) -> None: 96 """ standalone del logging """ 97 logging.warning("Deleting: %s", self)
98
[docs] 99 def _debug_del_dec(self, fn:Func) -> Callable: 100 """ wraps existing del method """ 101 102 def _wrapped(_self:object, *args, **kwargs) -> None: 103 logging.warning("Deleting: %s", _self) 104 fn(_self, *args, **kwargs) 105 106 return _wrapped
107 108 @override 109 def __call__[T](self, cls:type[T]) -> type[T]: 110 """ 111 A Class Decorator, attaches a debugging statement to the object destructor 112 """ 113 match (DEBUG_DESTRUCT_ON, hasattr(cls, "__del__")): 114 case (False, _): 115 pass 116 case (True, True): 117 setattr(cls, "__del__", self._debug_del_dec(cls.__del__)) # type: ignore[attr-defined] # noqa: B010 118 case (True, False): 119 setattr(cls, "__del__", self._debug_del) # noqa: B010 120 return cls