muutils.logger.exception_context
1from __future__ import annotations 2 3import json 4from types import TracebackType 5from typing import Protocol 6 7from muutils.json_serialize import json_serialize 8 9 10class WritableStream(Protocol): 11 """Protocol for objects that support write operations.""" 12 13 def write(self, __s: str) -> int: ... 14 15 16class ExceptionContext: 17 """context manager which catches all exceptions happening while the context is open, `.write()` the exception trace to the given stream, and then raises the exception 18 19 20 for example: 21 22 ```python 23 errorfile = open('error.log', 'w') 24 25 with ExceptionContext(errorfile): 26 # do something that might throw an exception 27 # if it does, the exception trace will be written to errorfile 28 # and then the exception will be raised 29 ``` 30 31 """ 32 33 def __init__(self, stream: WritableStream) -> None: 34 self.stream: WritableStream = stream 35 36 def __enter__(self) -> ExceptionContext: 37 return self 38 39 def __exit__( 40 self, 41 exc_type: type[BaseException] | None, 42 exc_value: BaseException | None, 43 exc_traceback: TracebackType | None, 44 ) -> bool: 45 if exc_type is not None: 46 self.stream.write( 47 json.dumps( 48 json_serialize( 49 { 50 "exc_type": exc_type, 51 "exc_value": exc_value, 52 "exc_traceback": exc_traceback, 53 } 54 ) 55 ) 56 ) 57 return False 58 return True
class
WritableStream(typing.Protocol):
11class WritableStream(Protocol): 12 """Protocol for objects that support write operations.""" 13 14 def write(self, __s: str) -> int: ...
Protocol for objects that support write operations.
WritableStream(*args, **kwargs)
1945def _no_init_or_replace_init(self, *args, **kwargs): 1946 cls = type(self) 1947 1948 if cls._is_protocol: 1949 raise TypeError('Protocols cannot be instantiated') 1950 1951 # Already using a custom `__init__`. No need to calculate correct 1952 # `__init__` to call. This can lead to RecursionError. See bpo-45121. 1953 if cls.__init__ is not _no_init_or_replace_init: 1954 return 1955 1956 # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`. 1957 # The first instantiation of the subclass will call `_no_init_or_replace_init` which 1958 # searches for a proper new `__init__` in the MRO. The new `__init__` 1959 # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent 1960 # instantiation of the protocol subclass will thus use the new 1961 # `__init__` and no longer call `_no_init_or_replace_init`. 1962 for base in cls.__mro__: 1963 init = base.__dict__.get('__init__', _no_init_or_replace_init) 1964 if init is not _no_init_or_replace_init: 1965 cls.__init__ = init 1966 break 1967 else: 1968 # should not happen 1969 cls.__init__ = object.__init__ 1970 1971 cls.__init__(self, *args, **kwargs)
class
ExceptionContext:
17class ExceptionContext: 18 """context manager which catches all exceptions happening while the context is open, `.write()` the exception trace to the given stream, and then raises the exception 19 20 21 for example: 22 23 ```python 24 errorfile = open('error.log', 'w') 25 26 with ExceptionContext(errorfile): 27 # do something that might throw an exception 28 # if it does, the exception trace will be written to errorfile 29 # and then the exception will be raised 30 ``` 31 32 """ 33 34 def __init__(self, stream: WritableStream) -> None: 35 self.stream: WritableStream = stream 36 37 def __enter__(self) -> ExceptionContext: 38 return self 39 40 def __exit__( 41 self, 42 exc_type: type[BaseException] | None, 43 exc_value: BaseException | None, 44 exc_traceback: TracebackType | None, 45 ) -> bool: 46 if exc_type is not None: 47 self.stream.write( 48 json.dumps( 49 json_serialize( 50 { 51 "exc_type": exc_type, 52 "exc_value": exc_value, 53 "exc_traceback": exc_traceback, 54 } 55 ) 56 ) 57 ) 58 return False 59 return True
context manager which catches all exceptions happening while the context is open, .write() the exception trace to the given stream, and then raises the exception
for example:
errorfile = open('error.log', 'w')
with ExceptionContext(errorfile):
# do something that might throw an exception
# if it does, the exception trace will be written to errorfile
# and then the exception will be raised
ExceptionContext(stream: WritableStream)
stream: WritableStream