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, 169 ANSI, 170 get_console, 171 fill_ansi, 172 highlight_pipes, 173 _init, 174 ) 175 from meerschaum.utils.packages import import_rich, attempt_import 176 from meerschaum.config import get_config 177 _ = import_rich() 178 rich_traceback = attempt_import('rich.traceback') 179 error_config = get_config('formatting', 'errors', patch=True) 180 message = ' ' + error_config[CHARSET]['icon'] + ' ' + str(message) 181 exception = exception_with_traceback(message, exception_class, stacklevel=3) 182 color_message = str(message) 183 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 184 if ANSI and not nopretty: 185 _init() 186 color_message = '\n' + fill_ansi(highlight_pipes(message), **error_config['ansi']['rich']) 187 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 188 try: 189 trace = rich_traceback.Traceback.extract( 190 exception_class, exception, exception.__traceback__ 191 ) 192 rtb = rich_traceback.Traceback(trace) 193 except Exception: 194 trace, rtb = None, None 195 if trace is None or rtb is None: 196 nopretty = True 197 if not nopretty and stack: 198 if get_console() is not None: 199 get_console().print(rtb) 200 if raise_: 201 raise color_exception 202 203 204def info(message: str, icon: bool = True, **kw): 205 """Print an informative message.""" 206 from meerschaum.utils.formatting import ( 207 CHARSET, 208 ANSI, 209 highlight_pipes, 210 fill_ansi, 211 _init, 212 ) 213 from meerschaum.config import get_config 214 info_config = get_config('formatting', 'info', patch=True) 215 if icon: 216 message = ' ' + info_config[CHARSET]['icon'] + ' ' + message 217 if ANSI: 218 _init() 219 message = highlight_pipes(message) 220 lines = message.split('\n') 221 message = fill_ansi(lines[0], **info_config['ansi']['rich']) + ( 222 '\n' + '\n'.join(lines[1:]) if len(lines) > 1 else '' 223 ) 224 print(message, flush=True)
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):
205def info(message: str, icon: bool = True, **kw): 206 """Print an informative message.""" 207 from meerschaum.utils.formatting import ( 208 CHARSET, 209 ANSI, 210 highlight_pipes, 211 fill_ansi, 212 _init, 213 ) 214 from meerschaum.config import get_config 215 info_config = get_config('formatting', 'info', patch=True) 216 if icon: 217 message = ' ' + info_config[CHARSET]['icon'] + ' ' + message 218 if ANSI: 219 _init() 220 message = highlight_pipes(message) 221 lines = message.split('\n') 222 message = fill_ansi(lines[0], **info_config['ansi']['rich']) + ( 223 '\n' + '\n'.join(lines[1:]) if len(lines) > 1 else '' 224 ) 225 print(message, flush=True)
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, 170 ANSI, 171 get_console, 172 fill_ansi, 173 highlight_pipes, 174 _init, 175 ) 176 from meerschaum.utils.packages import import_rich, attempt_import 177 from meerschaum.config import get_config 178 _ = import_rich() 179 rich_traceback = attempt_import('rich.traceback') 180 error_config = get_config('formatting', 'errors', patch=True) 181 message = ' ' + error_config[CHARSET]['icon'] + ' ' + str(message) 182 exception = exception_with_traceback(message, exception_class, stacklevel=3) 183 color_message = str(message) 184 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 185 if ANSI and not nopretty: 186 _init() 187 color_message = '\n' + fill_ansi(highlight_pipes(message), **error_config['ansi']['rich']) 188 color_exception = exception_with_traceback(color_message, exception_class, stacklevel=3) 189 try: 190 trace = rich_traceback.Traceback.extract( 191 exception_class, exception, exception.__traceback__ 192 ) 193 rtb = rich_traceback.Traceback(trace) 194 except Exception: 195 trace, rtb = None, None 196 if trace is None or rtb is None: 197 nopretty = True 198 if not nopretty and stack: 199 if get_console() is not None: 200 get_console().print(rtb) 201 if raise_: 202 raise color_exception
Raise an exception with supressed traceback.
def
dprint( msg: str, leader: bool = True, timestamp: 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:
32def dprint( 33 msg: str, 34 leader: bool = True, 35 timestamp: bool = True, 36 package: bool = True, 37 color: Optional[Union[str, List[str]]] = None, 38 attrs: Optional[List[str]] = None, 39 nopretty: bool = False, 40 _progress: Optional['rich.progress.Progress'] = None, 41 _task: Optional[int] = None, 42 **kw 43) -> None: 44 """Print a debug message.""" 45 if attrs is None: 46 attrs = [] 47 if not isinstance(color, bool) and not nopretty: 48 try: 49 from meerschaum.utils.formatting import CHARSET, ANSI, colored 50 except Exception as e: 51 CHARSET, ANSI, colored = 'ascii', False, None 52 from meerschaum.config._paths import CONFIG_DIR_PATH, PERMANENT_PATCH_DIR_PATH 53 from meerschaum.config import _config 54 cf = _config('formatting') 55 _color = color 56 else: 57 CHARSET, ANSI, colored, _color, cf = 'ascii', False, None, None, None 58 59 if timestamp: 60 from meerschaum.utils.dtypes import get_current_timestamp 61 now = get_current_timestamp('ms').replace(tzinfo=None) 62 else: 63 now = None 64 65 import logging, sys, inspect 66 logging.basicConfig(format='%(message)s') 67 log = logging.getLogger(__name__) 68 69 parent_frame = inspect.stack()[1][0] 70 parent_info = inspect.getframeinfo(parent_frame) 71 parent_lineno = parent_info.lineno 72 parent_globals = parent_frame.f_globals 73 parent_package = parent_globals['__name__'] 74 msg = str(msg) 75 premsg = "" 76 77 if now: 78 premsg = now.isoformat().split('T', maxsplit=1)[-1][:-3] + (' | ' if package else ':') 79 if package: 80 premsg = premsg + parent_package + ':' + str(parent_lineno) 81 if premsg: 82 premsg += "\n" 83 if leader and cf is not None: 84 try: 85 debug_leader = cf['formatting']['debug'][CHARSET]['icon'] if cf is not None else '' 86 except KeyError: 87 print( 88 "Failed to load config. " + 89 "Please delete the following directories and restart Meerschaum:" 90 ) 91 for p in [CONFIG_DIR_PATH, PERMANENT_PATCH_DIR_PATH]: 92 print(' - ' + str(p)) 93 debug_leader = '' 94 premsg = ' ' + debug_leader + ' ' + premsg 95 96 if ANSI: 97 if _color is not None: 98 if isinstance(_color, str): 99 _color = [_color] 100 else: 101 if cf is not None and not nopretty: 102 try: 103 _color = cf['formatting']['debug']['ansi']['rich'] if cf is not None else {} 104 except KeyError: 105 _color = {} 106 else: 107 _color = {} 108 if colored is not None: 109 premsg = colored(premsg, **_color) 110 111 if _progress is not None: 112 rich_text = _import_rich_text_for_dprint() 113 text = rich_text.Text.from_ansi(premsg + msg) 114 _progress.console.log(text) 115 else: 116 print(premsg + msg)
Print a debug message.