meerschaum.utils.warnings
Handle all things warnings and errors.
1#! /usr/bin/env python 2# -*- coding: utf-8 -*- 3# vim:fenc=utf-8 4 5""" 6Handle all things warnings and errors. 7""" 8 9from __future__ import annotations 10from meerschaum.utils.typing import Any, Union 11from meerschaum.utils.debug import dprint 12 13import sys 14import warnings 15 16__all__ = ( 17 'warn', 18 'info', 19 'error', 20 'dprint', 21) 22 23warnings.filterwarnings( 24 "always", 25 category = UserWarning 26) 27warnings.filterwarnings( 28 "always", 29 category = ImportWarning 30) 31warnings.filterwarnings( 32 "ignore", 33 category = RuntimeWarning 34) 35 36 37def enable_depreciation_warnings(name) -> None: 38 """Enable depreciation warnings in the warnings module.""" 39 import meerschaum.actions 40 warnings.filterwarnings( 41 "always", 42 category = DeprecationWarning, 43 module = name 44 ) 45 46def warn(*args, stacklevel=2, stack=True, color: bool = True, **kw) -> None: 47 """ 48 Print a stylized warning message. 49 May be captured by `warnings.filterwarnings()`. 50 """ 51 if stacklevel is None: 52 stacklevel = 1 53 stack = False 54 _old_sw = warnings.showwarning 55 56 get_config = None 57 if color: 58 try: 59 from meerschaum.utils.formatting import ( 60 CHARSET, ANSI, colored, fill_ansi, highlight_pipes, _init 61 ) 62 except ImportError: 63 CHARSET = 'ascii' 64 ANSI = False 65 try: 66 from meerschaum.config import get_config as _get_config 67 from meerschaum.config import _config 68 cf = _config() 69 get_config = _get_config 70 except ImportError: 71 get_config = None 72 73 if get_config is None and color: 74 try: 75 warn_config = cf['formatting']['warnings'] 76 except KeyError: 77 warn_config = { 78 'ansi' : {'color' : []}, 79 'unicode' : {'icon' : ''}, 80 'ascii' : {'icon' : ''}, 81 } 82 elif color: 83 warn_config = get_config('formatting', 'warnings', patch=True) 84 a = list(args) 85 a[0] = ' ' + (warn_config[CHARSET]['icon'] if color else '') + ' ' + str(a[0]) 86 if color: 87 if ANSI: 88 _init() 89 a[0] = fill_ansi(highlight_pipes(a[0]), **warn_config['ansi']['rich']) 90 91 ### Optionally omit the warning location. 92 def _no_stack_sw(message, category, filename, lineno, file=None, line=None): 93 sys.stderr.write(str(message) + '\n') 94 95 if not stack: 96 warnings.showwarning = _no_stack_sw 97 warnings.warn(*a, stacklevel=stacklevel, **kw) 98 if not stack: 99 warnings.showwarning = _old_sw 100 101 102def exception_with_traceback( 103 message: str, 104 exception_class = Exception, 105 stacklevel = 1, 106 tb_type = 'single' 107 ): 108 """Traceback construction help found here: 109 https://stackoverflow.com/questions/27138440/how-to-create-a-traceback-object 110 """ 111 import types 112 tb, depth = None, 0 113 while True: 114 try: 115 frame = sys._getframe(depth) 116 depth += 1 117 except ValueError as e: 118 break 119 120 tb = types.TracebackType(tb, frame, frame.f_lasti, frame.f_lineno) 121 122 tbs, _tb = [], tb 123 while True: 124 if _tb is None: 125 break 126 tbs.append(_tb) 127 _tb = _tb.tb_next 128 129 found_main, main_i = False, 0 130 first_mrsm_after_main = None 131 last_mrsm_i = None 132 tbs[(-1 * stacklevel)].tb_next = None 133 for i, _tb in enumerate([_tb for _tb in tbs]): 134 if 'meerschaum' in str(_tb.tb_frame) and '__main__.py' in str(_tb.tb_frame): 135 found_main = True 136 main_i = i 137 continue 138 if i >= (len(tbs) - (stacklevel - 1)): 139 tbs[i] = None 140 elif ( 141 found_main and 'meerschaum' in str(_tb.tb_frame) 142 and first_mrsm_after_main is None 143 and 'Shell' not in str(_tb.tb_frame) 144 ): 145 first_mrsm_after_main = i 146 elif 'meerschaum' in str(_tb.tb_frame): 147 last_mrsm_i = i 148 149 tbs = [_tb for _tb in tbs if tb is not None] 150 151 if tb_type == 'single': 152 return exception_class(message).with_traceback(tbs[-3]) 153 return exception_class(message).with_traceback(tbs[first_mrsm_after_main]) 154 155 156def error( 157 message: str, 158 exception_class = Exception, 159 nopretty: bool = False, 160 silent: bool = True, 161 stack: bool = True, 162 raise_: bool = True, 163): 164 """ 165 Raise an exception with supressed traceback. 166 """ 167 from meerschaum.utils.formatting import ( 168 CHARSET, ANSI, get_console, fill_ansi, highlight_pipes, _init 169 ) 170 from meerschaum.utils.packages import import_rich, attempt_import 171 from meerschaum.config import get_config 172 import types, inspect 173 rich = import_rich() 174 rich_traceback = attempt_import('rich.traceback') 175 error_config = get_config('formatting', 'errors', patch=True) 176 message = ' ' + error_config[CHARSET]['icon'] + ' ' + str(message) 177 exception = exception_with_traceback(message, exception_class, stacklevel=3) 178 color_message = str(message) 179 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 180 if ANSI and not nopretty: 181 _init() 182 color_message = '\n' + fill_ansi(highlight_pipes(message), **error_config['ansi']['rich']) 183 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 184 try: 185 trace = rich_traceback.Traceback.extract( 186 exception_class, exception, exception.__traceback__ 187 ) 188 rtb = rich_traceback.Traceback(trace) 189 except Exception as e: 190 trace, rtb = None, None 191 if trace is None or rtb is None: 192 nopretty = True 193 if not nopretty and stack: 194 if get_console() is not None: 195 get_console().print(rtb) 196 frame = sys._getframe(len(inspect.stack()) - 1) 197 if raise_: 198 raise color_exception 199 200 201def info(message: str, icon: bool = True, **kw): 202 """Print an informative message.""" 203 from meerschaum.utils.packages import import_rich, attempt_import 204 from meerschaum.utils.formatting import ( 205 CHARSET, ANSI, highlight_pipes, fill_ansi, _init 206 ) 207 from meerschaum.config import get_config 208 info_config = get_config('formatting', 'info', patch=True) 209 if icon: 210 message = ' ' + info_config[CHARSET]['icon'] + ' ' + message 211 if ANSI: 212 _init() 213 message = highlight_pipes(message) 214 lines = message.split('\n') 215 message = fill_ansi(lines[0], **info_config['ansi']['rich']) + ( 216 '\n' + '\n'.join(lines[1:]) if len(lines) > 1 else '' 217 ) 218 print(message)
def
warn(*args, stacklevel=2, stack=True, color: bool = True, **kw) -> None:
47def warn(*args, stacklevel=2, stack=True, color: bool = True, **kw) -> None: 48 """ 49 Print a stylized warning message. 50 May be captured by `warnings.filterwarnings()`. 51 """ 52 if stacklevel is None: 53 stacklevel = 1 54 stack = False 55 _old_sw = warnings.showwarning 56 57 get_config = None 58 if color: 59 try: 60 from meerschaum.utils.formatting import ( 61 CHARSET, ANSI, colored, fill_ansi, highlight_pipes, _init 62 ) 63 except ImportError: 64 CHARSET = 'ascii' 65 ANSI = False 66 try: 67 from meerschaum.config import get_config as _get_config 68 from meerschaum.config import _config 69 cf = _config() 70 get_config = _get_config 71 except ImportError: 72 get_config = None 73 74 if get_config is None and color: 75 try: 76 warn_config = cf['formatting']['warnings'] 77 except KeyError: 78 warn_config = { 79 'ansi' : {'color' : []}, 80 'unicode' : {'icon' : ''}, 81 'ascii' : {'icon' : ''}, 82 } 83 elif color: 84 warn_config = get_config('formatting', 'warnings', patch=True) 85 a = list(args) 86 a[0] = ' ' + (warn_config[CHARSET]['icon'] if color else '') + ' ' + str(a[0]) 87 if color: 88 if ANSI: 89 _init() 90 a[0] = fill_ansi(highlight_pipes(a[0]), **warn_config['ansi']['rich']) 91 92 ### Optionally omit the warning location. 93 def _no_stack_sw(message, category, filename, lineno, file=None, line=None): 94 sys.stderr.write(str(message) + '\n') 95 96 if not stack: 97 warnings.showwarning = _no_stack_sw 98 warnings.warn(*a, stacklevel=stacklevel, **kw) 99 if not stack: 100 warnings.showwarning = _old_sw
Print a stylized warning message.
May be captured by warnings.filterwarnings()
.
def
info(message: str, icon: bool = True, **kw):
202def info(message: str, icon: bool = True, **kw): 203 """Print an informative message.""" 204 from meerschaum.utils.packages import import_rich, attempt_import 205 from meerschaum.utils.formatting import ( 206 CHARSET, ANSI, highlight_pipes, fill_ansi, _init 207 ) 208 from meerschaum.config import get_config 209 info_config = get_config('formatting', 'info', patch=True) 210 if icon: 211 message = ' ' + info_config[CHARSET]['icon'] + ' ' + message 212 if ANSI: 213 _init() 214 message = highlight_pipes(message) 215 lines = message.split('\n') 216 message = fill_ansi(lines[0], **info_config['ansi']['rich']) + ( 217 '\n' + '\n'.join(lines[1:]) if len(lines) > 1 else '' 218 ) 219 print(message)
Print an informative message.
def
error( message: str, exception_class=<class 'Exception'>, nopretty: bool = False, silent: bool = True, stack: bool = True, raise_: bool = True):
157def error( 158 message: str, 159 exception_class = Exception, 160 nopretty: bool = False, 161 silent: bool = True, 162 stack: bool = True, 163 raise_: bool = True, 164): 165 """ 166 Raise an exception with supressed traceback. 167 """ 168 from meerschaum.utils.formatting import ( 169 CHARSET, ANSI, get_console, fill_ansi, highlight_pipes, _init 170 ) 171 from meerschaum.utils.packages import import_rich, attempt_import 172 from meerschaum.config import get_config 173 import types, inspect 174 rich = import_rich() 175 rich_traceback = attempt_import('rich.traceback') 176 error_config = get_config('formatting', 'errors', patch=True) 177 message = ' ' + error_config[CHARSET]['icon'] + ' ' + str(message) 178 exception = exception_with_traceback(message, exception_class, stacklevel=3) 179 color_message = str(message) 180 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 181 if ANSI and not nopretty: 182 _init() 183 color_message = '\n' + fill_ansi(highlight_pipes(message), **error_config['ansi']['rich']) 184 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 185 try: 186 trace = rich_traceback.Traceback.extract( 187 exception_class, exception, exception.__traceback__ 188 ) 189 rtb = rich_traceback.Traceback(trace) 190 except Exception as e: 191 trace, rtb = None, None 192 if trace is None or rtb is None: 193 nopretty = True 194 if not nopretty and stack: 195 if get_console() is not None: 196 get_console().print(rtb) 197 frame = sys._getframe(len(inspect.stack()) - 1) 198 if raise_: 199 raise color_exception
Raise an exception with supressed traceback.
def
dprint( msg: str, leader: bool = True, package: bool = True, color: Union[str, List[str], NoneType] = None, attrs: Optional[List[str]] = None, nopretty: bool = False, _progress: Optional[rich.progress.Progress] = None, _task: Optional[int] = None, **kw) -> None:
13def dprint( 14 msg: str, 15 leader: bool = True, 16 package: bool = True, 17 color: Optional[Union[str, List[str]]] = None, 18 attrs: Optional[List[str]] = None, 19 nopretty: bool = False, 20 _progress: Optional['rich.progress.Progress'] = None, 21 _task: Optional[int] = None, 22 **kw 23 ) -> None: 24 """Print a debug message.""" 25 if attrs is None: 26 attrs = [] 27 if not isinstance(color, bool) and not nopretty: 28 try: 29 from meerschaum.utils.formatting import CHARSET, ANSI, colored 30 except Exception as e: 31 CHARSET, ANSI, colored = 'ascii', False, None 32 from meerschaum.config._paths import CONFIG_DIR_PATH, PERMANENT_PATCH_DIR_PATH 33 from meerschaum.config import _config 34 cf = _config('formatting') 35 _color = color 36 else: 37 CHARSET, ANSI, colored, _color, cf = 'ascii', False, None, None, None 38 39 import logging, sys, inspect 40 logging.basicConfig(format='%(message)s') 41 log = logging.getLogger(__name__) 42 43 parent_frame = inspect.stack()[1][0] 44 parent_info = inspect.getframeinfo(parent_frame) 45 parent_lineno = parent_info.lineno 46 parent_globals = parent_frame.f_globals 47 parent_package = parent_globals['__name__'] 48 msg = str(msg) 49 premsg = "" 50 if package: 51 premsg = parent_package + ':' + str(parent_lineno) + '\n' 52 if leader and cf is not None: 53 try: 54 debug_leader = cf['formatting']['debug'][CHARSET]['icon'] if cf is not None else '' 55 except KeyError: 56 print( 57 "Failed to load config. " + 58 "Please delete the following directories and restart Meerschaum:" 59 ) 60 for p in [CONFIG_DIR_PATH, PERMANENT_PATCH_DIR_PATH]: 61 print(' - ' + str(p)) 62 debug_leader = '' 63 premsg = ' ' + debug_leader + ' ' + premsg 64 65 if ANSI: 66 if _color is not None: 67 if isinstance(_color, str): 68 _color = [_color] 69 else: 70 if cf is not None and not nopretty: 71 try: 72 _color = cf['formatting']['debug']['ansi']['rich'] if cf is not None else {} 73 except KeyError: 74 _color = {} 75 else: 76 _color = {} 77 if colored is not None: 78 premsg = colored(premsg, **_color) 79 if _progress is not None: 80 from meerschaum.utils.packages import import_rich, attempt_import 81 rich = import_rich() 82 rich_text = attempt_import('rich.text') 83 text = rich_text.Text.from_ansi(premsg + msg) 84 _progress.console.log(text) 85 else: 86 print(premsg + msg)
Print a debug message.