# Orca # # Copyright 2005-2008 Sun Microsystems Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Boston MA 02110-1301 USA. """Handles writing debugging messages to the debug file or stderr.""" import inspect import re import sys import threading import traceback from datetime import datetime, timezone from typing import Any, TextIO from .ax_utilities_debugging import AXUtilitiesDebugging LEVEL_OFF = 10000 LEVEL_SEVERE = 1000 LEVEL_WARNING = 900 LEVEL_INFO = 800 LEVEL_ALL = 0 # Leave these as-is for now so as not to break debugging for anyone using orca-customizations.py # pylint: disable=invalid-name debugLevel: int = LEVEL_SEVERE debugFile: TextIO | None = None # pylint: enable=invalid-name _printing = threading.local() def print_exception(level: int) -> None: """Prints out information regarding the current exception.""" if level >= debugLevel: _print_text(level) traceback.print_exc(100, debugFile) _print_text(level) def print_tokens( level: int, tokens: list[Any], timestamp: bool = False, stack: bool = False, ) -> None: """Prints out each token as a human-consumable string.""" if level < debugLevel: return text = " ".join(map(AXUtilitiesDebugging.as_string, tokens)) text = re.sub(r" (?=[,.:)])(?![\n])", "", text) _print_text(level, text, timestamp, stack) def print_message(level: int, text: str, timestamp: bool = False, stack: bool = False) -> None: """Prints out text.""" if level < debugLevel: return _print_text(level, text, timestamp, stack) def _stack_as_string(max_frames: int = 4) -> str: callers = [] current_module = inspect.getmodule(inspect.currentframe()) stack = inspect.stack() for i in range(1, len(stack)): frame = stack[i] module = inspect.getmodule(frame[0]) if module == current_module: continue if frame.function == "main": continue if module is None or module.__name__ is None: continue callers.append(frame) if len(callers) >= max_frames: break callers.reverse() return " > ".join(map(AXUtilitiesDebugging.as_string, callers)) def _print_text(level: int, text: str = "", timestamp: bool = False, stack: bool = False) -> None: if level < debugLevel: return # Prevent reentrancy. if getattr(_printing, "active", False): return _printing.active = True if timestamp: text = text.replace("\n", f"\n{' ' * 18}") local_time = datetime.now(tz=timezone.utc).astimezone() text = f"{local_time.strftime('%H:%M:%S.%f')} - {text}" if stack: text += f" {_stack_as_string()}" if debugFile: try: debugFile.writelines([text, "\n"]) except (AttributeError, OSError): _printing.active = False return except (TypeError, ValueError, UnicodeEncodeError) as error: text = f"Exception trying to write text to file: {error}" debugFile.writelines([text, "\n"]) else: try: sys.stderr.writelines([text, "\n"]) except (AttributeError, OSError): _printing.active = False return except (TypeError, ValueError, UnicodeEncodeError) as error: text = f"Exception trying to write text to stderr: {error}" sys.stderr.writelines([text, "\n"]) _printing.active = False