#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # IMPORTS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from code.local.io import *; from code.local.misc import *; from code.local.system import *; from code.local.typing import *; from datetime import timedelta; from code.core.metrics import *; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # GLOBAL VARIABLES # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _logging_prefix: str = ''; _quietmode: bool = False; _debugmode: bool = False; _ctr: Counter = Counter(); # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # METHOD get/set quiet mode, logging depth, timer # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def GetQuietMode() -> bool: return _quietmode; def SetQuietMode(mode: bool): global _quietmode; _quietmode = mode; return; def GetDebugMode() -> bool: return _debugmode; def SetDebugMode(mode: bool): global _debugmode; _debugmode = mode; return; def RestartCounter(): global _ctr; _ctr.reset(); return; def AddToCounter(n: int = 1): global _ctr; _ctr.add(n); return; def NumberOfSteps() -> int: return _ctr.numberOfStep; def TimeElapsed() -> timedelta: global _ctr; _ctr.stop(); return _ctr.elapsedTime; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Logging # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def logGeneric(tag: str, *lines: Any, file: io.TextIOWrapper, force: bool = False, tag_all: bool = True): if not force and _quietmode: return; tag = '' if tag == '' else tag + ' '; file = file or sys.stdout; for line in lines: print('{}{}{}'.format('', tag, line), file=file); if not tag_all: tag = ''; return; def logPlain(*lines: Any, force: bool = False, file: Any = None): logGeneric('', *lines, force=force, file=file or sys.stdout); def logInfo(*lines: Any, force: bool = False, tag_all: bool = True, file: Any = None): logGeneric('[\033[94;1mINFO\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stdout); def logDebug(*lines: Any, force: bool = False, tag_all: bool = True, file: Any = None): if not _debugmode: return; logGeneric('\033[2m[\033[96;1mDEBUG\033[0m\033[2m]\033[0m', *[ '\033[2m{}\033[0m'.format(line) for line in lines ], force=force, tag_all=tag_all, file=file or sys.stdout ); def logWarn(*lines: Any, force: bool = False, tag_all: bool = False, file: Any = None): logGeneric('[\033[93;1mWARNING\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stdout); def logError(*lines: Any, force: bool = False, tag_all: bool = False, file: Any = None): logGeneric('[\033[91;1mERROR\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stderr); def logFatal(*lines: Any, force: bool = False, tag_all: bool = False, file: Any = None): logGeneric('[\033[91;1mFATAL\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stderr); exit(1); # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # User Input # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def askUserInput(message: str, expectedformat: Callable) -> Union[str, None]: answer = None; while True: try: answer = input('{}{}'.format(_logging_prefix, message)); ## Meta+C erkennen: except KeyboardInterrupt: logPlain(''); return None; ## Meta+D erkennen: except EOFError: logPlain(''); return None; except: continue; if expectedformat(answer): break; return answer; def askConfirmation(message: str, default: bool = False) -> bool: answer = askUserInput(message, lambda x: not not re.match(r'^(y|yes|j|ja|n|no|nein)$', x)); if isinstance(answer, str): return True if re.match(r'^(y|yes|j|ja)$', answer) else False; return default;