meerschaum.utils.debug
Functions to handle debug statements
1#! /usr/bin/env python 2# -*- coding: utf-8 -*- 3# vim:fenc=utf-8 4 5""" 6Functions to handle debug statements 7""" 8 9from __future__ import annotations 10 11from datetime import datetime, timezone 12import meerschaum as mrsm 13from meerschaum.utils.typing import Union, Optional, List 14 15 16_rich_text = None 17def _import_rich_text_for_dprint(): 18 """ 19 Avoid calling `attempt_import()` on every dprint. 20 """ 21 global _rich_text 22 if _rich_text is not None: 23 return _rich_text 24 25 from meerschaum.utils.packages import import_rich, attempt_import 26 _ = import_rich() 27 _rich_text = attempt_import('rich.text', lazy=False) 28 return _rich_text 29 30 31def dprint( 32 msg: str, 33 leader: bool = True, 34 timestamp: bool = True, 35 package: bool = True, 36 color: Optional[Union[str, List[str]], bool] = None, 37 attrs: Optional[List[str]] = None, 38 nopretty: bool = False, 39 _progress: Optional['rich.progress.Progress'] = None, 40 _task: Optional[int] = None, 41 _package: Optional[str] = None, 42 _lineno: Optional[int] = None, 43 **kw 44) -> None: 45 """ 46 Print a debug message to stderr. 47 48 The header names the calling module and line. The Rust core passes its own module path and 49 line as `_package` and `_lineno` (its debug events have no Python caller). 50 """ 51 import meerschaum.config.paths as paths 52 if attrs is None: 53 attrs = [] 54 55 if not isinstance(color, bool) and not nopretty: 56 try: 57 from meerschaum.utils.formatting import CHARSET, ANSI, colored 58 except Exception as e: 59 CHARSET, ANSI, colored = 'ascii', False, None 60 from meerschaum.config import _config 61 cf = _config('formatting') 62 _color = color 63 else: 64 CHARSET, ANSI, colored, _color, cf = 'ascii', False, None, None, None 65 66 if timestamp: 67 from meerschaum.utils.dtypes import get_current_timestamp 68 now = get_current_timestamp('ms').replace(tzinfo=None) 69 else: 70 now = None 71 72 import logging, sys, inspect 73 logging.basicConfig(format='%(message)s') 74 log = logging.getLogger(__name__) 75 76 if _package is not None: 77 parent_package = _package 78 parent_lineno = _lineno 79 else: 80 parent_frame = inspect.stack()[1][0] 81 parent_info = inspect.getframeinfo(parent_frame) 82 parent_lineno = parent_info.lineno 83 parent_globals = parent_frame.f_globals 84 parent_package = parent_globals['__name__'] 85 msg = str(msg) 86 premsg = "" 87 88 if now: 89 premsg = now.isoformat().split('T', maxsplit=1)[-1][:-3] + (' | ' if package else ':') 90 if package: 91 premsg = premsg + parent_package + ( 92 (':' + str(parent_lineno)) if parent_lineno is not None else '' 93 ) 94 if premsg: 95 premsg += "\n" 96 if leader and cf is not None: 97 try: 98 debug_leader = cf['formatting']['debug'][CHARSET]['icon'] if cf is not None else '' 99 except KeyError: 100 print( 101 "Failed to load config. " + 102 "Please delete the following directories and restart Meerschaum:" 103 ) 104 for p in [paths.CONFIG_DIR_PATH, paths.PERMANENT_PATCH_DIR_PATH]: 105 print(' - ' + str(p)) 106 debug_leader = '' 107 premsg = ' ' + debug_leader + ' ' + premsg 108 109 if ANSI: 110 if _color is not None: 111 if isinstance(_color, str): 112 _color = [_color] 113 else: 114 if cf is not None and not nopretty: 115 try: 116 _color = cf['formatting']['debug']['ansi']['rich'] if cf is not None else {} 117 except KeyError: 118 _color = {} 119 else: 120 _color = {} 121 if colored is not None: 122 premsg = colored(premsg, **_color) 123 124 if _progress is not None: 125 rich_text = _import_rich_text_for_dprint() 126 text = rich_text.Text.from_ansi(premsg + msg) 127 _progress.console.log(text) 128 else: 129 ### v5: debug output goes to stderr (v4 printed to stdout), like warnings and the 130 ### Rust core's debug output. Job logs capture both streams. 131 print(premsg + msg, file=sys.stderr) 132 133 134def _checkpoint( 135 _progress: Optional['rich.progress.Progress'] = None, 136 _task: Optional[int] = None, 137 _total: Optional[int] = None, 138 **kw 139) -> None: 140 """If the `_progress` and `_task` objects are provided, increment the task by one step. 141 If `_total` is provided, update the total instead. 142 """ 143 if _progress is not None and _task is not None: 144 _kw = {'total': _total} if _total is not None else {'advance': 1} 145 _progress.update(_task, **_kw) 146 147 148def trace(browser: bool = True): 149 """ 150 Open a web-based debugger to trace the execution of the program. 151 """ 152 from meerschaum.utils.packages import attempt_import 153 heartrate = attempt_import('heartrate') 154 heartrate.trace(files=heartrate.files.all, browser=browser)
def
dprint( msg: str, leader: bool = True, timestamp: bool = True, package: bool = True, color: 'Optional[Union[str, List[str]], bool]' = None, attrs: List[str] | None = None, nopretty: bool = False, _progress: rich.progress.Progress | None = None, _task: int | None = None, _package: str | None = None, _lineno: int | None = 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]], bool] = None, 38 attrs: Optional[List[str]] = None, 39 nopretty: bool = False, 40 _progress: Optional['rich.progress.Progress'] = None, 41 _task: Optional[int] = None, 42 _package: Optional[str] = None, 43 _lineno: Optional[int] = None, 44 **kw 45) -> None: 46 """ 47 Print a debug message to stderr. 48 49 The header names the calling module and line. The Rust core passes its own module path and 50 line as `_package` and `_lineno` (its debug events have no Python caller). 51 """ 52 import meerschaum.config.paths as paths 53 if attrs is None: 54 attrs = [] 55 56 if not isinstance(color, bool) and not nopretty: 57 try: 58 from meerschaum.utils.formatting import CHARSET, ANSI, colored 59 except Exception as e: 60 CHARSET, ANSI, colored = 'ascii', False, None 61 from meerschaum.config import _config 62 cf = _config('formatting') 63 _color = color 64 else: 65 CHARSET, ANSI, colored, _color, cf = 'ascii', False, None, None, None 66 67 if timestamp: 68 from meerschaum.utils.dtypes import get_current_timestamp 69 now = get_current_timestamp('ms').replace(tzinfo=None) 70 else: 71 now = None 72 73 import logging, sys, inspect 74 logging.basicConfig(format='%(message)s') 75 log = logging.getLogger(__name__) 76 77 if _package is not None: 78 parent_package = _package 79 parent_lineno = _lineno 80 else: 81 parent_frame = inspect.stack()[1][0] 82 parent_info = inspect.getframeinfo(parent_frame) 83 parent_lineno = parent_info.lineno 84 parent_globals = parent_frame.f_globals 85 parent_package = parent_globals['__name__'] 86 msg = str(msg) 87 premsg = "" 88 89 if now: 90 premsg = now.isoformat().split('T', maxsplit=1)[-1][:-3] + (' | ' if package else ':') 91 if package: 92 premsg = premsg + parent_package + ( 93 (':' + str(parent_lineno)) if parent_lineno is not None else '' 94 ) 95 if premsg: 96 premsg += "\n" 97 if leader and cf is not None: 98 try: 99 debug_leader = cf['formatting']['debug'][CHARSET]['icon'] if cf is not None else '' 100 except KeyError: 101 print( 102 "Failed to load config. " + 103 "Please delete the following directories and restart Meerschaum:" 104 ) 105 for p in [paths.CONFIG_DIR_PATH, paths.PERMANENT_PATCH_DIR_PATH]: 106 print(' - ' + str(p)) 107 debug_leader = '' 108 premsg = ' ' + debug_leader + ' ' + premsg 109 110 if ANSI: 111 if _color is not None: 112 if isinstance(_color, str): 113 _color = [_color] 114 else: 115 if cf is not None and not nopretty: 116 try: 117 _color = cf['formatting']['debug']['ansi']['rich'] if cf is not None else {} 118 except KeyError: 119 _color = {} 120 else: 121 _color = {} 122 if colored is not None: 123 premsg = colored(premsg, **_color) 124 125 if _progress is not None: 126 rich_text = _import_rich_text_for_dprint() 127 text = rich_text.Text.from_ansi(premsg + msg) 128 _progress.console.log(text) 129 else: 130 ### v5: debug output goes to stderr (v4 printed to stdout), like warnings and the 131 ### Rust core's debug output. Job logs capture both streams. 132 print(premsg + msg, file=sys.stderr)
Print a debug message to stderr.
The header names the calling module and line. The Rust core passes its own module path and
line as _package and _lineno (its debug events have no Python caller).
def
trace(browser: bool = True):
149def trace(browser: bool = True): 150 """ 151 Open a web-based debugger to trace the execution of the program. 152 """ 153 from meerschaum.utils.packages import attempt_import 154 heartrate = attempt_import('heartrate') 155 heartrate.trace(files=heartrate.files.all, browser=browser)
Open a web-based debugger to trace the execution of the program.