mirror of
https://github.com/vale981/master-thesis
synced 2025-03-06 02:21:38 -05:00
381 lines
11 KiB
Python
381 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
from __future__ import division, print_function
|
|
|
|
import os
|
|
import sys
|
|
import subprocess as sp
|
|
import logging
|
|
import platform
|
|
|
|
if platform.system() == 'Windows':
|
|
width_correction = -1
|
|
else:
|
|
width_correction = 0
|
|
|
|
try:
|
|
from shutil import get_terminal_size as shutil_get_terminal_size
|
|
except ImportError:
|
|
shutil_get_terminal_size = None
|
|
|
|
class MultiLineFormatter(logging.Formatter):
|
|
"""pads a multiline log message with spaces such that
|
|
|
|
<HEAD> msg_line1
|
|
msg_line2
|
|
...
|
|
"""
|
|
def format(self, record):
|
|
_str = logging.Formatter.format(self, record)
|
|
header = _str.split(record.message)[0]
|
|
_str = _str.replace('\n', '\n' + ' '*len(header))
|
|
return _str
|
|
|
|
def_handl = logging.StreamHandler(stream = sys.stderr) # the default handler simply uses stderr
|
|
def_handl.setLevel(logging.DEBUG) # ... listens to all messaged
|
|
fmt = MultiLineFormatter('%(asctime)s %(name)s %(levelname)s : %(message)s')
|
|
def_handl.setFormatter(fmt) # ... and pads multiline messaged
|
|
log = logging.getLogger(__name__) # creates the default log for this module
|
|
log.addHandler(def_handl)
|
|
|
|
def get_terminal_size(defaultw=80):
|
|
""" Checks various methods to determine the terminal size
|
|
|
|
|
|
Methods:
|
|
- shutil.get_terminal_size (only Python3)
|
|
- fcntl.ioctl
|
|
- subprocess.check_output
|
|
- os.environ
|
|
|
|
Parameters
|
|
----------
|
|
defaultw : int
|
|
Default width of terminal.
|
|
|
|
|
|
Returns
|
|
-------
|
|
width, height : int
|
|
Width and height of the terminal. If one of them could not be
|
|
found, None is return in its place.
|
|
|
|
"""
|
|
if hasattr(shutil_get_terminal_size, "__call__"):
|
|
return shutil_get_terminal_size()
|
|
else:
|
|
try:
|
|
import fcntl, termios, struct
|
|
fd = 0
|
|
hw = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
|
|
'1234'))
|
|
return (hw[1], hw[0])
|
|
except:
|
|
try:
|
|
out = sp.check_output(["tput", "cols"])
|
|
width = int(out.decode("utf-8").strip())
|
|
return (width, None)
|
|
except:
|
|
try:
|
|
hw = (os.environ['LINES'], os.environ['COLUMNS'])
|
|
return (hw[1], hw[0])
|
|
except:
|
|
return (defaultw, None)
|
|
|
|
|
|
def get_terminal_width(default=80, name=None):
|
|
try:
|
|
width = get_terminal_size(defaultw=default)[0] + width_correction
|
|
# print("got width from get_terminal_size", width)
|
|
except:
|
|
width = default
|
|
# print("use default width", width)
|
|
return width
|
|
|
|
|
|
def terminal_reserve(progress_obj, terminal_obj=None, identifier=None):
|
|
""" Registers the terminal (stdout) for printing.
|
|
|
|
Useful to prevent multiple processes from writing progress bars
|
|
to stdout.
|
|
|
|
One process (server) prints to stdout and a couple of subprocesses
|
|
do not print to the same stdout, because the server has reserved it.
|
|
Of course, the clients have to be nice and check with
|
|
terminal_reserve first if they should (not) print.
|
|
Nothing is locked.
|
|
|
|
Returns
|
|
-------
|
|
True if reservation was successful (or if we have already reserved this tty),
|
|
False if there already is a reservation from another instance.
|
|
"""
|
|
if terminal_obj is None:
|
|
terminal_obj = sys.stdout
|
|
|
|
if identifier is None:
|
|
identifier = ''
|
|
|
|
if terminal_obj in TERMINAL_RESERVATION: # terminal was already registered
|
|
log.debug("this terminal %s has already been added to reservation list", terminal_obj)
|
|
|
|
if TERMINAL_RESERVATION[terminal_obj] is progress_obj:
|
|
log.debug("we %s have already reserved this terminal %s", progress_obj, terminal_obj)
|
|
return True
|
|
else:
|
|
log.debug("someone else %s has already reserved this terminal %s", TERMINAL_RESERVATION[terminal_obj],
|
|
terminal_obj)
|
|
return False
|
|
else: # terminal not yet registered
|
|
log.debug("terminal %s was reserved for us %s", terminal_obj, progress_obj)
|
|
TERMINAL_RESERVATION[terminal_obj] = progress_obj
|
|
return True
|
|
|
|
|
|
def terminal_unreserve(progress_obj, terminal_obj=None, verbose=0, identifier=None):
|
|
""" Unregisters the terminal (stdout) for printing.
|
|
|
|
an instance (progress_obj) can only unreserve the tty (terminal_obj) when it also reserved it
|
|
|
|
see terminal_reserved for more information
|
|
|
|
Returns
|
|
-------
|
|
None
|
|
"""
|
|
|
|
if terminal_obj is None:
|
|
terminal_obj = sys.stdout
|
|
|
|
if identifier is None:
|
|
identifier = ''
|
|
else:
|
|
identifier = identifier + ': '
|
|
|
|
po = TERMINAL_RESERVATION.get(terminal_obj)
|
|
if po is None:
|
|
log.debug("terminal %s was not reserved, nothing happens", terminal_obj)
|
|
else:
|
|
if po is progress_obj:
|
|
log.debug("terminal %s now unreserned", terminal_obj)
|
|
del TERMINAL_RESERVATION[terminal_obj]
|
|
else:
|
|
log.debug("you %s can NOT unreserve terminal %s be cause it was reserved by %s", progress_obj, terminal_obj,
|
|
po)
|
|
|
|
def len_string_without_ESC(s):
|
|
return len(remove_ESC_SEQ_from_string(s))
|
|
|
|
def remove_ESC_SEQ_from_string(s):
|
|
old_idx = 0
|
|
new_s = ""
|
|
ESC_CHAR_START = "\033["
|
|
while True:
|
|
idx = s.find(ESC_CHAR_START, old_idx)
|
|
if idx == -1:
|
|
break
|
|
j = 2
|
|
while s[idx+j] in '0123456789':
|
|
j += 1
|
|
|
|
new_s += s[old_idx:idx]
|
|
old_idx = idx+j+1
|
|
|
|
new_s += s[old_idx:]
|
|
return new_s
|
|
|
|
# for esc_seq in ESC_SEQ_SET:
|
|
# s = s.replace(esc_seq, '')
|
|
# return s
|
|
|
|
def _close_kind(stack, which_kind):
|
|
stack_tmp = []
|
|
s = ""
|
|
|
|
# close everything until which_kind is found
|
|
while True:
|
|
kind, start, end = stack.pop()
|
|
if kind != which_kind:
|
|
s += end
|
|
stack_tmp.append((kind, start, end))
|
|
else:
|
|
break
|
|
|
|
# close which_kind
|
|
s = end
|
|
|
|
# start everything that was closed before which_kind
|
|
for kind, start, end in stack_tmp:
|
|
s += start
|
|
stack.append((kind, start, end))
|
|
|
|
return s
|
|
|
|
def _close_all(stack):
|
|
s = ""
|
|
for kind, start, end in stack:
|
|
s += end
|
|
return s
|
|
|
|
def _open_color(stack, color):
|
|
start = '<span style="color:{}">'.format(color)
|
|
end = '</span>'
|
|
stack.append(('color', start, end))
|
|
return start
|
|
|
|
def _open_bold(stack):
|
|
start = '<b>'
|
|
end = '</b>'
|
|
stack.append(('bold', start, end))
|
|
return start
|
|
|
|
def ESC_SEQ_to_HTML(s):
|
|
old_idx = 0
|
|
new_s = ""
|
|
ESC_CHAR_START = "\033["
|
|
color_on = False
|
|
bold_on = False
|
|
stack = []
|
|
while True:
|
|
idx = s.find(ESC_CHAR_START, old_idx)
|
|
if idx == -1:
|
|
break
|
|
j = 2
|
|
while s[idx + j] in '0123456789':
|
|
j += 1
|
|
|
|
new_s += s[old_idx:idx]
|
|
old_idx = idx + j + 1
|
|
escseq = s[idx:idx+j+1]
|
|
|
|
if escseq in ESC_COLOR_TO_HTML: # set color
|
|
if color_on:
|
|
new_s += _close_kind(stack, which_kind = 'color')
|
|
new_s += _open_color(stack, ESC_COLOR_TO_HTML[escseq])
|
|
color_on = True
|
|
elif escseq == ESC_DEFAULT: # unset color
|
|
if color_on:
|
|
new_s += _close_kind(stack, which_kind = 'color')
|
|
color_on = False
|
|
elif escseq == ESC_BOLD:
|
|
if not bold_on:
|
|
new_s += _open_bold(stack)
|
|
bold_on = True
|
|
elif escseq == ESC_RESET_BOLD:
|
|
if bold_on:
|
|
new_s += _close_kind(stack, which_kind = 'bold')
|
|
bold_on = False
|
|
elif escseq == ESC_NO_CHAR_ATTR:
|
|
if color_on:
|
|
new_s += _close_kind(stack, which_kind = 'color')
|
|
color_on = False
|
|
if bold_on:
|
|
new_s += _close_kind(stack, which_kind = 'bold')
|
|
bold_on = False
|
|
else:
|
|
pass
|
|
|
|
new_s += s[old_idx:]
|
|
new_s += _close_all(stack)
|
|
|
|
return new_s
|
|
|
|
def ESC_MOVE_LINE_UP(n):
|
|
return "\033[{}A".format(n)
|
|
|
|
|
|
def ESC_MOVE_LINE_DOWN(n):
|
|
return "\033[{}B".format(n)
|
|
|
|
ESC_NO_CHAR_ATTR = "\033[0m"
|
|
|
|
ESC_BOLD = "\033[1m"
|
|
ESC_DIM = "\033[2m"
|
|
ESC_UNDERLINED = "\033[4m"
|
|
ESC_BLINK = "\033[5m"
|
|
ESC_INVERTED = "\033[7m"
|
|
ESC_HIDDEN = "\033[8m"
|
|
|
|
ESC_MY_MAGIC_ENDING = ESC_HIDDEN + ESC_NO_CHAR_ATTR
|
|
|
|
# not widely supported, use '22' instead
|
|
# ESC_RESET_BOLD = "\033[21m"
|
|
|
|
ESC_RESET_DIM = "\033[22m"
|
|
ESC_RESET_BOLD = ESC_RESET_DIM
|
|
|
|
ESC_RESET_UNDERLINED = "\033[24m"
|
|
ESC_RESET_BLINK = "\033[25m"
|
|
ESC_RESET_INVERTED = "\033[27m"
|
|
ESC_RESET_HIDDEN = "\033[28m"
|
|
|
|
ESC_DEFAULT = "\033[39m"
|
|
ESC_BLACK = "\033[30m"
|
|
ESC_RED = "\033[31m"
|
|
ESC_GREEN = "\033[32m"
|
|
ESC_YELLOW = "\033[33m"
|
|
ESC_BLUE = "\033[34m"
|
|
ESC_MAGENTA = "\033[35m"
|
|
ESC_CYAN = "\033[36m"
|
|
ESC_LIGHT_GREY = "\033[37m"
|
|
ESC_DARK_GREY = "\033[90m"
|
|
ESC_LIGHT_RED = "\033[91m"
|
|
ESC_LIGHT_GREEN = "\033[92m"
|
|
ESC_LIGHT_YELLOW = "\033[93m"
|
|
ESC_LIGHT_BLUE = "\033[94m"
|
|
ESC_LIGHT_MAGENTA = "\033[95m"
|
|
ESC_LIGHT_CYAN = "\033[96m"
|
|
ESC_WHITE = "\033[97m"
|
|
|
|
ESC_COLOR_TO_HTML = {
|
|
ESC_BLACK : '#000000',
|
|
ESC_RED : '#800000',
|
|
ESC_GREEN : '#008000',
|
|
ESC_YELLOW : '#808000',
|
|
ESC_BLUE : '#000080',
|
|
ESC_MAGENTA : '#800080',
|
|
ESC_CYAN : '#008080',
|
|
ESC_LIGHT_GREY : '#c0c0c0',
|
|
ESC_DARK_GREY : '#808080',
|
|
ESC_LIGHT_RED : '#ff0000',
|
|
ESC_LIGHT_GREEN : '#00ff00',
|
|
ESC_LIGHT_YELLOW : '#ffff00',
|
|
ESC_LIGHT_BLUE : '#0000ff',
|
|
ESC_LIGHT_MAGENTA : '#ff00ff',
|
|
ESC_LIGHT_CYAN : '#00ffff',
|
|
ESC_WHITE : '#ffffff'}
|
|
|
|
ESC_SEQ_SET = [ESC_NO_CHAR_ATTR,
|
|
ESC_BOLD,
|
|
ESC_DIM,
|
|
ESC_UNDERLINED,
|
|
ESC_BLINK,
|
|
ESC_INVERTED,
|
|
ESC_HIDDEN,
|
|
ESC_RESET_BOLD,
|
|
ESC_RESET_DIM,
|
|
ESC_RESET_UNDERLINED,
|
|
ESC_RESET_BLINK,
|
|
ESC_RESET_INVERTED,
|
|
ESC_RESET_HIDDEN,
|
|
ESC_DEFAULT,
|
|
ESC_BLACK,
|
|
ESC_RED,
|
|
ESC_GREEN,
|
|
ESC_YELLOW,
|
|
ESC_BLUE,
|
|
ESC_MAGENTA,
|
|
ESC_CYAN,
|
|
ESC_LIGHT_GREY,
|
|
ESC_DARK_GREY,
|
|
ESC_LIGHT_RED,
|
|
ESC_LIGHT_GREEN,
|
|
ESC_LIGHT_YELLOW,
|
|
ESC_LIGHT_BLUE,
|
|
ESC_LIGHT_MAGENTA,
|
|
ESC_LIGHT_CYAN,
|
|
ESC_WHITE]
|
|
|
|
# terminal reservation list, see terminal_reserve
|
|
TERMINAL_RESERVATION = {}
|
|
# these are classes that print progress bars, see terminal_reserve
|
|
TERMINAL_PRINT_LOOP_CLASSES = ["ProgressBar", "ProgressBarCounter", "ProgressBarFancy", "ProgressBarCounterFancy"]
|