From c2060bdb422f8780c10bd69b578c99110a69bab5 Mon Sep 17 00:00:00 2001 From: Honza Mach <honza.mach.ml@gmail.com> Date: Thu, 9 Mar 2017 10:42:35 +0100 Subject: [PATCH] Minor changes in code and documentation, preparations for unit tests --- pydgets/cowsay.py | 2 +- pydgets/tests/__init__.py | 0 pydgets/tests/test_widgets.py | 37 ++++ pydgets/widgets.py | 348 +++++++++++++++++++++------------- 4 files changed, 255 insertions(+), 132 deletions(-) create mode 100644 pydgets/tests/__init__.py create mode 100644 pydgets/tests/test_widgets.py diff --git a/pydgets/cowsay.py b/pydgets/cowsay.py index 01d71d6..170ccb5 100644 --- a/pydgets/cowsay.py +++ b/pydgets/cowsay.py @@ -1 +1 @@ -#https://github.com/piuccio/cowsay +# TODO: Implement library similar to the https://github.com/piuccio/cowsay diff --git a/pydgets/tests/__init__.py b/pydgets/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pydgets/tests/test_widgets.py b/pydgets/tests/test_widgets.py new file mode 100644 index 0000000..3a78a79 --- /dev/null +++ b/pydgets/tests/test_widgets.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +#------------------------------------------------------------------------------- +# Copyright (C) since 2016 Jan Mach <honza.mach.ml@gmail.com> +# Use of this source is governed by the MIT license, see LICENSE file. +#------------------------------------------------------------------------------- + +import unittest +from unittest.mock import Mock, MagicMock, call +from pprint import pformat, pprint + +import os +import sys +import shutil + +# Generate the path to custom 'lib' directory +#lib = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')) +#sys.path.insert(0, lib) + +import pydgets.widgets + +class TestWidgets(unittest.TestCase): + + def setUp(self): + pass + def tearDown(self): + pass + + def test_01_basic(self): + """ + Perform the basic operativity tests. + """ + self.assertTrue(True) + self.assertEqual(0, 0) + +if __name__ == "__main__": + unittest.main() diff --git a/pydgets/widgets.py b/pydgets/widgets.py index 3249af0..5c47ceb 100644 --- a/pydgets/widgets.py +++ b/pydgets/widgets.py @@ -1,12 +1,22 @@ #!/usr/bin/python3 # -*- coding: utf-8 -*- #------------------------------------------------------------------------------- -# Copyright (C) 2015-2016 Jan Mach <honza.mach.ml@gmail.com> +# Copyright (C) since 2016 Jan Mach <honza.mach.ml@gmail.com> # Use of this source is governed by the MIT license, see LICENSE file. #------------------------------------------------------------------------------- """ -Console widget library. +Console widget library for Python3. + +This library is intended to help in data presentation from various console scripts. +It provides tools for easy formating and rendering of many usefull 'widgets' like +lists, tree strutures, tables, etc. + +.. note:: + + Although production code is based on this library, it should still be considered + work in progress. + """ import os @@ -18,6 +28,8 @@ import time import pprint DFLT_TABLE_STYLE = 'utf8.b' + +# Detected terminal width and height TERMINAL_WIDTH = 0 TERMINAL_HEIGHT = 0 @@ -71,10 +83,11 @@ TEXT_FORMATING = { 'rst': '\033[0m', } +# Text alignment index TEXT_ALIGNMENT = { '<': '<', 'l': '<', 'left': '<', 'L': '<', 'LEFT': '<', '>': '>', 'r': '>', 'right': '>', 'R': '>', 'RIGHT': '>', - '^': '^', 'c': 'c', 'center': 'c', 'C': 'c', 'CENTER': 'c', + '^': '^', 'c': 'c', 'center': 'c', 'C': 'c', 'CENTER': 'c', } # Index of box/table border drawing characters (https://en.wikipedia.org/wiki/Box-drawing_character) @@ -115,7 +128,7 @@ BORDER_STYLES = { 'bh': '#', 'bv': '#', 'bl': '#', 'bm': '#', 'br': '#' }, 'utf8.a': { - # Alternativelly define the characters with unicode codes + # Alternativelly it is possible to define the characters with unicode codes #'th': '\u2500', 'tv': '\u2502', 'tl': '\u250c', 'tm': '\u252c', 'tr': '\u2510', #'mh': '\u2500', 'mv': '\u2502', 'ml': '\u251c', 'mm': '\u253c', 'mr': '\u2524', #'bh': '\u2500', 'bv': '\u2502', 'bl': '\u2514', 'bm': '\u2534', 'br': '\u2518' @@ -277,38 +290,41 @@ TREE_STYLES = { def terminal_size(): """ - Detect the size of terminal window in rows and columns. + Detect the current size of terminal window as a numer of rows and columns. """ try: (rows, columns) = os.popen('stty size', 'r').read().split() rows = int(rows) columns = int(columns) return (columns, rows) - + # Currently ignore any errors and return some reasonable default values. + # Errors may occur, when the library is used in non-terminal application + # like daemon. except: pass return (80, 24) +# Detect the terminal size automatically after library initialization (TERMINAL_WIDTH, TERMINAL_HEIGHT) = terminal_size() #------------------------------------------------------------------------------- class ConsoleWidget: """ - Base class for all console widgets. + Base class for all console widgets implemented by this library. This class provides basic common methods for widget setup and rendering. """ - + SETTING_FLAG_PLAIN = 'plain' """ Widget setting: Plain only output flag - + Setting this flag to True will force the widget to be displayed without any fancy terminal formating (colors, emphasis, etc.). """ - + SETTING_FLAG_ASCII = 'ascii' """ Widget setting: ASCII only output flag @@ -316,25 +332,25 @@ class ConsoleWidget: Setting this flag to True will force the widget to be displayed using only ASCII characters. """ - + SETTING_WIDTH = 'width' SETTING_ALIGN = 'align' - + SETTING_TEXT_FORMATING = 'text_formating' - + SETTING_DATA_FORMATING = 'data_formating' SETTING_DATA_TYPE = 'data_type' - + SETTING_PADDING = 'padding' SETTING_PADDING_CHAR = 'padding_char' SETTING_PADDING_LEFT = 'padding_left' SETTING_PADDING_RIGHT = 'padding_right' - + SETTING_MARGIN = 'margin' SETTING_MARGIN_CHAR = 'margin_char' SETTING_MARGIN_LEFT = 'margin_left' SETTING_MARGIN_RIGHT = 'margin_right' - + def __init__(self, content = None, **kwargs): """ Default object constructor. @@ -343,18 +359,18 @@ class ConsoleWidget: for setting in self.list_settings(): self._settings[setting[0]] = kwargs.get(setting[0], setting[1]) self.setup(content, **kwargs) - + def __str__(self): """ Overloaded operator for direct string output. """ return self.render() - + def list_settings(self): """ Get list of all appropriate settings and their default values. - The returned list is then used setup() and get_setup() methods to setup + The returned list is then used in setup() and get_setup() methods to setup the widget internal settings. """ return [ @@ -374,7 +390,7 @@ class ConsoleWidget: (self.SETTING_MARGIN_LEFT, None), (self.SETTING_MARGIN_RIGHT, None), ] - + def setup(self, content = None, **kwargs): """ Store settings internally. @@ -384,10 +400,10 @@ class ConsoleWidget: for setting in self.list_settings(): if setting[0] in kwargs: self._settings[setting[0]] = kwargs.get(setting[0]) - + def get_setup(self, content = None, **kwargs): """ - Get current setup by combining internal settings with the one given. + Get current setup by combining internal settings with the ones given. """ if content is None: content = self.content @@ -402,16 +418,16 @@ class ConsoleWidget: setup[setting[0]] = self._settings.get(setting[0]) return (content, setup) - + #--------------------------------------------------------------------------- - + @staticmethod def _es(settings, *keys): """ Extract given subset of widget settings. """ return {k: settings[k] for k in keys} - + @staticmethod def _es_data(settings): """ @@ -419,7 +435,7 @@ class ConsoleWidget: """ return {k: settings[k] for k in (ConsoleWidget.SETTING_DATA_FORMATING, ConsoleWidget.SETTING_DATA_TYPE)} - + @staticmethod def _es_content(settings): """ @@ -431,7 +447,7 @@ class ConsoleWidget: ConsoleWidget.SETTING_PADDING_LEFT, ConsoleWidget.SETTING_PADDING_RIGHT, ConsoleWidget.SETTING_PADDING_CHAR)} - + @staticmethod def _es_text(settings, text_formating = {}): """ @@ -440,7 +456,7 @@ class ConsoleWidget: s = {k: settings[k] for k in (ConsoleWidget.SETTING_FLAG_PLAIN,)} s.update(text_formating) return s - + @staticmethod def _es_margin(settings): """ @@ -450,9 +466,9 @@ class ConsoleWidget: ConsoleWidget.SETTING_MARGIN_LEFT, ConsoleWidget.SETTING_MARGIN_RIGHT, ConsoleWidget.SETTING_MARGIN_CHAR)} - + #--------------------------------------------------------------------------- - + @staticmethod def calculate_width_widget(width, margin = None, margin_left = None, margin_right = None): """ @@ -467,7 +483,7 @@ class ConsoleWidget: if margin_right is not None: width -= int(margin_right) return width if width > 0 else None - + @staticmethod def calculate_width_content(width, margin = None, margin_left = None, margin_right = None, padding = None, padding_left = None, padding_right = None): """ @@ -490,7 +506,7 @@ class ConsoleWidget: if padding_right is not None: width -= int(padding_right) return width if width > 0 else None - + @staticmethod def fmt_data(text, data_formating = None, data_type = None): """ @@ -501,7 +517,7 @@ class ConsoleWidget: elif data_formating: return str(data_formating).format(text) return str(text) - + @staticmethod def fmt_content(text, width = 0, align = '<', padding = None, padding_left = None, padding_right = None, padding_char = ' '): """ @@ -520,7 +536,7 @@ class ConsoleWidget: strptrn = '{:' + ('{}{}{}'.format(str(padding_char)[0], str(TEXT_ALIGNMENT[align]), str(width))) + 's}' text = strptrn.format(text) return text - + @staticmethod def fmt_text(text, bg = None, fg = None, attr = None, plain = False): """ @@ -536,7 +552,7 @@ class ConsoleWidget: if (fg is not None) or (bg is not None) or (attr is not None): text += TEXT_FORMATING['rst'] return text - + @staticmethod def fmt_margin(text, margin = None, margin_left = None, margin_right = None, margin_char = ' '): """ @@ -551,15 +567,15 @@ class ConsoleWidget: if margin_right is not None: text = '{}{}'.format(text, str(margin_char)[0] * int(margin_right)) return text - + #--------------------------------------------------------------------------- - + def _render(self, content, **settings): """ Perform widget rendering, but do not print anything. """ raise Exception("This method must be oveloaded and implemented in subclass") - + def render(self, content = None, **settings): """ Perform widget rendering, but do not print anything. @@ -573,13 +589,13 @@ class SingleLineWidget(ConsoleWidget): """ Base class for single line only widgets. """ - + def _render_content(self, content, **settings): """ Perform widget rendering, but do not print anything. """ raise Exception("This method must be oveloaded and implemented in subclass") - + def _render(self, content, **settings): """ Perform widget rendering, but do not print anything. @@ -590,7 +606,7 @@ class SingleLineWidget(ConsoleWidget): result = self.fmt_margin(result, **s) return result - + def display(self, content = None, **settings): """ Perform widget rendering and output the result. @@ -603,13 +619,13 @@ class MultiLineWidget(ConsoleWidget): """ Base class for widgets spanning over multiple lines. """ - + def _render_content(self, content, **settings): """ Perform widget rendering, but do not print anything. """ raise Exception("This method must be oveloaded and implemented in subclass") - + def _render(self, content, **settings): """ Perform widget rendering, but do not print anything. @@ -622,7 +638,7 @@ class MultiLineWidget(ConsoleWidget): result.append(self.fmt_margin(l, **s)) return result - + def display(self, content = None, **settings): """ Perform widget rendering and output the result. @@ -635,13 +651,13 @@ class BorderedMultiLineWidget(MultiLineWidget): """ Base class for bordered widgets spanning over multiple lines. """ - + SETTING_FLAG_BORDER = 'border' SETTING_BORDER_FORMATING = 'border_formating' SETTING_BORDER_STYLE = 'border_style' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -651,7 +667,7 @@ class BorderedMultiLineWidget(MultiLineWidget): result.append((self.SETTING_BORDER_FORMATING, {})) result.append((self.SETTING_BORDER_STYLE, 'utf8.a')) return result - + @staticmethod def bchar(posh, posv, border_style): """ @@ -659,9 +675,9 @@ class BorderedMultiLineWidget(MultiLineWidget): """ index = '{}{}'.format(posv, posh).lower() return BORDER_STYLES[border_style][index] - + #--------------------------------------------------------------------------- - + @staticmethod def calculate_width_widget_int(width, border = False, margin = None, margin_left = None, margin_right = None): """ @@ -678,7 +694,7 @@ class BorderedMultiLineWidget(MultiLineWidget): if border: width -= 2 return width if width > 0 else None - + @staticmethod def calculate_width_content(width, border = False, margin = None, margin_left = None, margin_right = None, padding = None, padding_left = None, padding_right = None): """ @@ -710,9 +726,9 @@ class TextWidget(SingleLineWidget): """ Implementation of formatable text widget. """ - + SETTING_TEXT_HIGHLIGHT = 'text_highlight' - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -720,7 +736,7 @@ class TextWidget(SingleLineWidget): result = super().list_settings() result.append((self.SETTING_TEXT_HIGHLIGHT, None)) return result - + #--------------------------------------------------------------------------- def _render_content(self, content, **settings): @@ -728,19 +744,19 @@ class TextWidget(SingleLineWidget): Perform widget rendering, but do not print anything. """ ocontent = content - + s = self._es_data(settings) content = self.fmt_data(content, **s) - + s = self._es_content(settings) content = self.fmt_content(content, **s) - + if settings[self.SETTING_TEXT_HIGHLIGHT]: s = self._es_text(settings, settings[self.SETTING_TEXT_HIGHLIGHT](ocontent)) else: s = self._es_text(settings, settings[self.SETTING_TEXT_FORMATING]) content = self.fmt_text(content, **s) - + s = self._es_margin(settings) content = self.fmt_margin(content, **s) @@ -752,7 +768,7 @@ class StatusLineWidget(TextWidget): """ Implementation of line widget. """ - + def _render_content(self, content, **settings): """ Perform widget rendering, but do not print anything. @@ -766,15 +782,15 @@ class ListWidget(MultiLineWidget): """ Implementation of list widget. """ - + INDENT = ' ' - + SETTING_LIST_FORMATING = 'list_formating' SETTING_LIST_STYLE = 'list_style' SETTING_LIST_TYPE = 'list_type' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -784,22 +800,22 @@ class ListWidget(MultiLineWidget): result.append((self.SETTING_LIST_STYLE, 'utf8.a')) result.append((self.SETTING_LIST_TYPE, 'unordered')) return result - + @staticmethod def lchar(list_style): """ Retrieve list bullet character for particular list style. """ return LIST_STYLES[list_style] - + #--------------------------------------------------------------------------- - + def _render_item(self, depth, key, value = None, **settings): """ Format single list item. """ strptrn = self.INDENT * depth - + lchar = self.lchar(settings[self.SETTING_LIST_STYLE]) s = self._es_text(settings, settings[self.SETTING_LIST_FORMATING]) lchar = self.fmt_text(lchar, **s) @@ -809,9 +825,9 @@ class ListWidget(MultiLineWidget): strptrn += ": {}" s = self._es_text(settings, settings[self.SETTING_TEXT_FORMATING]) strptrn = self.fmt_text(strptrn.format(key, value), **s) - + return '{} {} {}'.format(self.INDENT * depth, lchar, strptrn) - + def _render_content_list(self, content, depth, **settings): """ Render the list. @@ -830,7 +846,7 @@ class ListWidget(MultiLineWidget): result.append(self._render_item(depth, value, **settings)) i += 1 return result - + def _render_content_dict(self, content, depth, **settings): """ Render the dict. @@ -869,12 +885,12 @@ class TreeWidget(MultiLineWidget): """ Base class for all console widgets. """ - + SETTING_TREE_FORMATING = 'tree_formating' SETTING_TREE_STYLE = 'tree_style' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -883,7 +899,7 @@ class TreeWidget(MultiLineWidget): result.append((self.SETTING_TREE_FORMATING, {})) result.append((self.SETTING_TREE_STYLE, 'utf8.a')) return result - + @staticmethod def tchar(tree_style, cur_level, level, item, size): """ @@ -909,7 +925,7 @@ class TreeWidget(MultiLineWidget): Format single tree line. """ cur_depth = len(dstack) - 1 - + treeptrn = '' s = self._es_text(settings, settings[self.SETTING_TREE_FORMATING]) for ds in dstack: @@ -920,7 +936,7 @@ class TreeWidget(MultiLineWidget): strptrn += ": {}" s = self._es_text(settings, settings[self.SETTING_TEXT_FORMATING]) strptrn = self.fmt_text(strptrn.format(key, value), **s) - + return '{} {}'.format(treeptrn, strptrn) def _render_content_list(self, content, depth, dstack, **settings): @@ -984,13 +1000,13 @@ class BoxWidget(BorderedMultiLineWidget): """ Implementation of box widget. """ - + SETTING_FLAG_HEADER = 'header' SETTING_HEADER_CONTENT = 'header_content' SETTING_HEADER_FORMATING = 'header_formating' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -1000,16 +1016,16 @@ class BoxWidget(BorderedMultiLineWidget): result.append((self.SETTING_HEADER_CONTENT, 'Notice')) result.append((self.SETTING_HEADER_FORMATING, {})) return result - + def fmt_border(self, width, t = 'm', border_style = 'utf8.a', border_formating = {}): """ Format box separator line. """ border = self.bchar('l', t, border_style) + (self.bchar('h', t, border_style) * (width-2)) + self.bchar('r', t, border_style) return self.fmt_text(border, **border_formating) - + #--------------------------------------------------------------------------- - + @staticmethod def _wrap_content(content, width): """ @@ -1026,9 +1042,9 @@ class BoxWidget(BorderedMultiLineWidget): l = textwrap.wrap(d, width) lines += l return lines - + #--------------------------------------------------------------------------- - + def _render_border_line(self, t, settings): """ Render box border line. @@ -1040,27 +1056,27 @@ class BoxWidget(BorderedMultiLineWidget): s = self._es(settings, self.SETTING_MARGIN, self.SETTING_MARGIN_LEFT, self.SETTING_MARGIN_RIGHT, self.SETTING_MARGIN_CHAR) border_line = self.fmt_margin(border_line, **s) return border_line - + def _render_line(self, line, settings): """ Render single box line. """ s = self._es(settings, self.SETTING_WIDTH, self.SETTING_FLAG_BORDER, self.SETTING_MARGIN, self.SETTING_MARGIN_LEFT, self.SETTING_MARGIN_RIGHT) width_content = self.calculate_width_widget_int(**s) - + s = self._es_content(settings) s[self.SETTING_WIDTH] = width_content line = self.fmt_content(line, **s) - + s = self._es_text(settings, settings[self.SETTING_TEXT_FORMATING]) line = self.fmt_text(line, **s) - + s = self._es(settings, self.SETTING_BORDER_STYLE) bchar = self.bchar('v', 'm', **s) - + s = self._es_text(settings, settings[self.SETTING_BORDER_FORMATING]) bchar = self.fmt_text(bchar, **s) - + line = '{}{}{}'.format(bchar, line, bchar) s = self._es_margin(settings) line = self.fmt_margin(line, **s) @@ -1072,12 +1088,12 @@ class BoxWidget(BorderedMultiLineWidget): """ if not self.SETTING_WIDTH in settings or not settings[self.SETTING_WIDTH]: settings[self.SETTING_WIDTH] = TERMINAL_WIDTH - + s = {k: settings[k] for k in (self.SETTING_WIDTH, self.SETTING_FLAG_BORDER, self.SETTING_MARGIN, self.SETTING_MARGIN_LEFT, self.SETTING_MARGIN_RIGHT, self.SETTING_PADDING, self.SETTING_PADDING_LEFT, self.SETTING_PADDING_RIGHT)} width_int = self.calculate_width_content(**s) - + lines = self._wrap_content(content, width_int) - + result = [] if settings[self.SETTING_FLAG_BORDER]: result.append(self._render_border_line('t', settings)) @@ -1098,16 +1114,16 @@ class TableWidget(BorderedMultiLineWidget): """ Table result formater. """ - + SETTING_FLAG_HEADER = 'header' SETTING_HEADER_CONTENT = 'header_content' SETTING_HEADER_FORMATING = 'header_formating' SETTING_FLAG_ENUMERATE = 'enumerate' SETTING_COLUMNS = 'columns' SETTING_ROW_HIGHLIGHT = 'row_highlight' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -1120,7 +1136,7 @@ class TableWidget(BorderedMultiLineWidget): result.append((self.SETTING_COLUMNS, None)) result.append((self.SETTING_ROW_HIGHLIGHT, None)) return result - + def fmt_border(self, dimensions, t = 'm', border_style = 'utf8.a', border_formating = {}): """ Format table separator line. @@ -1131,7 +1147,7 @@ class TableWidget(BorderedMultiLineWidget): border = '{}{}{}'.format(self.bchar('l', t, border_style), self.bchar('m', t, border_style).join(cells), self.bchar('r', t, border_style)) return self.fmt_text(border, **border_formating) - + def fmt_cell(self, value, width, cell_formating, **text_formating): """ Format sigle table cell. @@ -1139,7 +1155,7 @@ class TableWidget(BorderedMultiLineWidget): strptrn = " {:" + '{:s}{:d}'.format(cell_formating.get('align', '<'), width) + "s} " strptrn = self.fmt_text(strptrn, **text_formating) return strptrn.format(value) - + def fmt_row(self, columns, dimensions, row, **settings): """ Format single table row. @@ -1158,16 +1174,16 @@ class TableWidget(BorderedMultiLineWidget): return self.bchar('v', 'm', settings[self.SETTING_BORDER_STYLE], **settings[self.SETTING_BORDER_FORMATING]) + \ self.bchar('v', 'm', settings[self.SETTING_BORDER_STYLE], **settings[self.SETTING_BORDER_FORMATING]).join(cells) + \ self.bchar('v', 'm', settings[self.SETTING_BORDER_STYLE], **settings[self.SETTING_BORDER_FORMATING]) - + def fmt_row_header(self, columns, dimensions, **settings): """ Format table header row. """ row = list(map(lambda x: x['label'], columns)) return self.fmt_row(columns, dimensions, row, **settings) - + #--------------------------------------------------------------------------- - + def table_format(self, columns, content): """ Enumerate each table column. @@ -1182,7 +1198,7 @@ class TableWidget(BorderedMultiLineWidget): i += 1 result.append(result_row) return (columns, result) - + def table_enumerate(self, columns, content): """ Enumerate each table column. @@ -1193,7 +1209,7 @@ class TableWidget(BorderedMultiLineWidget): i += 1 row.insert(0, '{:d}'.format(i)) return (columns, content) - + def table_measure(self, columns, content): """ Measure the width of each table column. @@ -1211,26 +1227,26 @@ class TableWidget(BorderedMultiLineWidget): ) i += 1 return dimensions - + #--------------------------------------------------------------------------- - + def _render_content(self, content, **settings): """ Perform widget rendering, but do not print anything. """ result = [] columns = settings[self.SETTING_COLUMNS] - + # Format each table cell into string. (columns, content) = self.table_format(columns, content) - + # Enumerate each table row. if settings[self.SETTING_FLAG_ENUMERATE]: (columns, content) = self.table_enumerate(columns, content) - + # Calculate the dimensions of each table column. dimensions = self.table_measure(columns, content) - + # Display table header. sb = {k: settings[k] for k in (self.SETTING_BORDER_STYLE, self.SETTING_BORDER_FORMATING)} result.append(self.fmt_border(dimensions, 't', **sb)) @@ -1239,13 +1255,13 @@ class TableWidget(BorderedMultiLineWidget): s[self.SETTING_TEXT_FORMATING] = settings[self.SETTING_HEADER_FORMATING] result.append(self.fmt_row_header(columns, dimensions, **s)) result.append(self.fmt_border(dimensions, 'm', **sb)) - + # Display table body. for row in content: s = {k: settings[k] for k in (self.SETTING_FLAG_PLAIN, self.SETTING_BORDER_STYLE, self.SETTING_BORDER_FORMATING)} s[self.SETTING_TEXT_FORMATING] = settings[self.SETTING_TEXT_FORMATING] result.append(self.fmt_row(columns, dimensions, row, **s)) - + # Display table footer result.append(self.fmt_border(dimensions, 'b', **sb)) return result @@ -1260,9 +1276,9 @@ class ProgressBarWidget(SingleLineWidget): SETTING_BAR_FORMATING = 'bar_formating' SETTING_BAR_CHAR = 'bar_char' SETTING_BAR_WIDTH = 'bar_width' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -1272,9 +1288,9 @@ class ProgressBarWidget(SingleLineWidget): result.append((self.SETTING_BAR_CHAR, '=')) result.append((self.SETTING_BAR_WIDTH, 0)) return result - + #--------------------------------------------------------------------------- - + def _render_content(self, content, **settings): """ Perform widget rendering, but do not print anything. @@ -1290,7 +1306,7 @@ class ProgressBarWidget(SingleLineWidget): progress = self.fmt_text(progress, **s) progress += ' ' * int(bar_len - int(bar_len * percent)) return "{:6.2f}% [{:s}]".format(percent * 100, progress) - + def display(self, content = None, **settings): """ Perform widget rendering and output the result. @@ -1310,9 +1326,9 @@ class BarChartWidget(MultiLineWidget): SETTING_BAR_CHAR = 'bar_char' SETTING_BAR_WIDTH = 'bar_width' SETTING_BARS = 'bars' - + #--------------------------------------------------------------------------- - + def list_settings(self): """ Get list of all appropriate settings and their default values. @@ -1323,7 +1339,7 @@ class BarChartWidget(MultiLineWidget): result.append((self.SETTING_BAR_WIDTH, 0)) result.append((self.SETTING_BARS, None)) return result - + def chart_measure(self, bars): """ Measure the width of each table column. @@ -1337,9 +1353,9 @@ class BarChartWidget(MultiLineWidget): bar.get('width_min', 0), # configured column minimal width ) return width - + #--------------------------------------------------------------------------- - + def _render_bar(self, bar, value, max_value, label_width, bar_width, **settings): """ Render single chart bar. @@ -1353,14 +1369,14 @@ class BarChartWidget(MultiLineWidget): barstr += ' ' * int(bar_width - int(bar_width * percent)) strptrn = "{:"+str(label_width)+"s} [{:s}]" return strptrn.format(bar.get('label'), barstr) - + def _render_content(self, content, **settings): """ Perform widget rendering, but do not print anything. """ result = [] bars = settings[self.SETTING_BARS] - + label_width = self.chart_measure(bars) if not settings[self.SETTING_BAR_WIDTH]: settings[self.SETTING_BAR_WIDTH] = TERMINAL_WIDTH - label_width - 3 @@ -1373,21 +1389,51 @@ class BarChartWidget(MultiLineWidget): if __name__ == "__main__": """ - Perform the demonstration. + Perform the library demonstration. """ + + widget_groups = ['all', 'data', 'text', 'line', 'box', 'list', 'tree', 'table', 'progress', 'barchart'] + section_separator = "\n --------------------------------------------\n" argparser = argparse.ArgumentParser(description = "pydgets - Console widget library for Python 3") - argparser.add_argument('--group', help = 'pick a group of widgets', choices = ['all', 'data', 'text', 'line', 'box', 'list', 'tree', 'table', 'progress', 'barchart'], default='all') + argparser.add_argument('--group', help = 'pick a group of widgets', choices = widget_groups, default='all') args = argparser.parse_args() + print(""" + ============================================== + _____ _ _ + | __ \ | | | | + | |__) |_ _ __| | __ _ ___ | |_ ___ + | ___/| | | | / _` | / _` | / _ \| __|/ __| + | | | |_| || (_| || (_| || __/| |_ \__ \\ + |_| \__, | \__,_| \__, | \___| \__||___/ + __/ | __/ | + |___/ |___/ + + ============================================== + ıllıllı PYTHON3 CONSOLE WIDGET LIBRARY ıllıllı + ============================================== + +""") + + argparser.print_help() + print(section_separator) + + #--------------------------------------------------------------------------- + (columns, rows) = terminal_size() print("Detected terminal size {} x {} (WxH)".format(columns, rows)) + print(section_separator) + + #--------------------------------------------------------------------------- if args.group in ('all', 'data'): print("") - labelptrn = " {:<60s} " - textw = TextWidget() print("Demonstrations of TextWidget data formating capabilities...") print("") + + labelptrn = " {:<60s} " + textw = TextWidget() + for conv in ( [523689, 'int'], [123523.689111, 'float'], @@ -1400,7 +1446,8 @@ if __name__ == "__main__": label = " Data conversion '{}' to '{}'".format(conv[0], conv[1]) label = labelptrn.format(label) print(label, textw.render(conv[0], data_type = conv[1])) - + + print("") print("Demonstrations of TextWidget data highlighting capabilities...") print("") @@ -1412,8 +1459,13 @@ if __name__ == "__main__": for val in ('50', '150'): label = " Data decoration '{}'".format(val) + label = labelptrn.format(label) print(label, textw.render(val, text_highlight = deco)) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'text'): print("") labelptrn = " {:<60s} " @@ -1456,6 +1508,10 @@ if __name__ == "__main__": label = labelptrn.format(label) print(labelptrn.format(label), textw.render(label, text_formating = {"fg": fg, "bg": bg, "attr": attr})) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'line'): print("") print("Demonstrations of StatusLineWidget...") @@ -1466,6 +1522,10 @@ if __name__ == "__main__": print(linew.render('Test status line text, right align, right padding with custom character', padding_right = 5, padding_char = '#', align = '>', text_formating = {"bg": "on_blue"})) print(linew.render('Test status line text, margin', margin = 5, text_formating = {"bg": "on_yellow"})) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'list'): print("") print("Demonstrations of ListWidget...") @@ -1498,6 +1558,10 @@ if __name__ == "__main__": listw = ListWidget() listw.display(data) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'tree'): print("") print("Demonstrations of TreeWidget...") @@ -1531,7 +1595,11 @@ if __name__ == "__main__": } treew = TreeWidget() treew.display(data, tree_style = s) - + + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'box'): print("") print("Demonstrations of BoxWidget...") @@ -1542,6 +1610,10 @@ if __name__ == "__main__": print("") boxw.display(text, header_content = h, width = 150, padding = 1, border_style = s, header_formating = {"bg": "on_red"}) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'table'): print("") print("Demonstrations of TableWidget...") @@ -1560,6 +1632,10 @@ if __name__ == "__main__": ] tablew.display(tbody, columns = tcols) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'progress'): print("") print("Demonstrations of ProgressBarWidget...") @@ -1569,6 +1645,10 @@ if __name__ == "__main__": progw.display(i/100) time.sleep(1) + print(section_separator) + + #--------------------------------------------------------------------------- + if args.group in ('all', 'barchart'): print("") print("Demonstrations of BarChartWidget...") @@ -1592,4 +1672,10 @@ if __name__ == "__main__": 324, 12, ] - barch.display(chbody, bars = chbars) + barch.display(chbody, bars = chbars, bar_formating = {"fg": "blue", "bg": "on_blue"}) + + print(section_separator) + + #--------------------------------------------------------------------------- + + argparser.print_help() -- GitLab