<commit_before># -*- coding: utf-8 -*-
'''
Display output in a table format
=================================

.. versionadded:: 2017.7.0

This outputter displays a sequence of rows as table.

Example output::

    edge01.bjm01:
    ----------
        comment:
        ----------
        out:
        ----------
            ______________________________________________________________________________
            | Active | Interface | Last Move |        Mac        | Moves | Static | Vlan |
            ______________________________________________________________________________
            |  True  |  ae1.900  |    0.0    | 40:A6:77:5A:50:01 |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.111  |    0.0    | 64:16:8D:32:26:58 |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.111  |    0.0    | 8C:60:4F:73:2D:57 |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.111  |    0.0    | 8C:60:4F:73:2D:7C |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.222  |    0.0    | 8C:60:4F:73:2D:57 |   0   | False  | 222  |
            ______________________________________________________________________________
            |  True  |  ae1.222  |    0.0    | F4:0F:1B:76:9D:97 |   0   | False  | 222  |
            ______________________________________________________________________________
        result:
        ----------
'''

# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals

import operator
from functools import reduce  # pylint: disable=redefined-builtin

# Import Salt libs
import salt.output
import salt.utils.color
import salt.utils.data
import salt.utils.locales

# Import 3rd-party libs
from salt.ext import six
from salt.ext.six.moves import map, zip  # pylint: disable=redefined-builtin

__virtualname__ = 'table'


def __virtual__():
    return __virtualname__


class TableDisplay(object):
    '''
    Manage the table display content.
    '''

    _JUSTIFY_MAP = {
        'center': six.text_type.center,
        'right': six.text_type.rjust,
        'left': six.text_type.ljust
    }

    def __init__(self,
                 has_header=True,  # if header will be displayed
                 row_delimiter='-',  # row delimiter char
                 delim=' | ',  # column delimiter
                 justify='center',  # text justify
                 separate_rows=True,  # display the line separating two consecutive rows
                 prefix='| ',  # character to display at the beginning of the row
                 suffix=' |',  # character to display at the end of the row
                 width=50,  # column max width
                 wrapfunc=None):  # function wrapper
        self.__dict__.update(
            salt.utils.color.get_colors(
                __opts__.get('color'),
                __opts__.get('color_theme')
            )
        )
        self.strip_colors = __opts__.get('strip_colors', True)

        self.has_header = has_header
        self.row_delimiter = row_delimiter
        self.delim = delim
        self.justify = justify
        self.separate_rows = separate_rows
        self.prefix = prefix
        self.suffix = suffix
        self.width = width

        if not(wrapfunc and callable(wrapfunc)):
            self.wrapfunc = self.wrap_onspace
        else:
            self.wrapfunc = wrapfunc

    def ustring(self,
                indent,
                color,
                msg,
                prefix='',
                suffix='',
                endc=None):
        '''Build the unicode string to be displayed.'''
        if endc is None:
            endc = self.ENDC  # pylint: disable=no-member

        indent *= ' '
        fmt = u'{0}{1}{2}{3}{4}{5}'

        try:
            return fmt.format(indent, color, prefix, msg, endc, suffix)
        except UnicodeDecodeError:
            return fmt.format(indent, color, prefix, salt.utils.locales.sdecode(msg), endc, suffix)

    def wrap_onspace(self, text):

        '''
        When the text inside the column is longer then the width, will split by space and continue on the next line.'''

        def _truncate(line, word):
            return '{line}{part}{word}'.format(
                        line=line,
                        part=' \n'[(len(line[line.rfind('\n')+1:]) + len(word.split('\n', 1)[0]) >= self.width)],
                        word=word
                    )

        return reduce(_truncate, text.split(' '))

    def prepare_rows(self,
                     rows,
                     indent,
                     has_header):

        '''Prepare rows content to be displayed.'''

        out = []

        def row_wrapper(row):
            new_rows = [
                self.wrapfunc(item).split('\n')
                for item in row
            ]
            rows = []
            for item in map(None, *new_rows):
                if isinstance(item, (tuple, list)):
                    rows.append([substr or '' for substr in item])
                else:
                    rows.append([item])
            return rows

        logical_rows = [
            row_wrapper(row)
            for row in rows
        ]

        columns = map(None, *reduce(operator.add, logical_rows))

        max_widths = [
            max([len(six.text_type(item)) for item in column])
            for column in columns
        ]
        row_separator = self.row_delimiter * (len(self.prefix) + len(self.suffix) + sum(max_widths) +
                                              len(self.delim) * (len(max_widths) - 1))

        justify = self._JUSTIFY_MAP[self.justify.lower()]

        if self.separate_rows:
            out.append(
                self.ustring(
                    indent,
                    self.LIGHT_GRAY,  # pylint: disable=no-member
                    row_separator
                )
            )
        for physical_rows in logical_rows:<commit_msg>Fix Python 3 incompatibility in table outputter<commit_after># -*- coding: utf-8 -*-
'''
Display output in a table format
=================================

.. versionadded:: 2017.7.0

This outputter displays a sequence of rows as table.

Example output::

    edge01.bjm01:
    ----------
        comment:
        ----------
        out:
        ----------
            ______________________________________________________________________________
            | Active | Interface | Last Move |        Mac        | Moves | Static | Vlan |
            ______________________________________________________________________________
            |  True  |  ae1.900  |    0.0    | 40:A6:77:5A:50:01 |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.111  |    0.0    | 64:16:8D:32:26:58 |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.111  |    0.0    | 8C:60:4F:73:2D:57 |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.111  |    0.0    | 8C:60:4F:73:2D:7C |   0   | False  | 111  |
            ______________________________________________________________________________
            |  True  |  ae1.222  |    0.0    | 8C:60:4F:73:2D:57 |   0   | False  | 222  |
            ______________________________________________________________________________
            |  True  |  ae1.222  |    0.0    | F4:0F:1B:76:9D:97 |   0   | False  | 222  |
            ______________________________________________________________________________
        result:
        ----------
'''

# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals

import operator
from functools import reduce  # pylint: disable=redefined-builtin

# Import Salt libs
import salt.output
import salt.utils.color
import salt.utils.data
import salt.utils.locales

# Import 3rd-party libs
from salt.ext import six
from salt.ext.six.moves import map, zip  # pylint: disable=redefined-builtin

__virtualname__ = 'table'


def __virtual__():
    return __virtualname__


class TableDisplay(object):
    '''
    Manage the table display content.
    '''

    _JUSTIFY_MAP = {
        'center': six.text_type.center,
        'right': six.text_type.rjust,
        'left': six.text_type.ljust
    }

    def __init__(self,
                 has_header=True,  # if header will be displayed
                 row_delimiter='-',  # row delimiter char
                 delim=' | ',  # column delimiter
                 justify='center',  # text justify
                 separate_rows=True,  # display the line separating two consecutive rows
                 prefix='| ',  # character to display at the beginning of the row
                 suffix=' |',  # character to display at the end of the row
                 width=50,  # column max width
                 wrapfunc=None):  # function wrapper
        self.__dict__.update(
            salt.utils.color.get_colors(
                __opts__.get('color'),
                __opts__.get('color_theme')
            )
        )
        self.strip_colors = __opts__.get('strip_colors', True)

        self.has_header = has_header
        self.row_delimiter = row_delimiter
        self.delim = delim
        self.justify = justify
        self.separate_rows = separate_rows
        self.prefix = prefix
        self.suffix = suffix
        self.width = width

        if not(wrapfunc and callable(wrapfunc)):
            self.wrapfunc = self.wrap_onspace
        else:
            self.wrapfunc = wrapfunc

    def ustring(self,
                indent,
                color,
                msg,
                prefix='',
                suffix='',
                endc=None):
        '''Build the unicode string to be displayed.'''
        if endc is None:
            endc = self.ENDC  # pylint: disable=no-member

        indent *= ' '
        fmt = u'{0}{1}{2}{3}{4}{5}'

        try:
            return fmt.format(indent, color, prefix, msg, endc, suffix)
        except UnicodeDecodeError:
            return fmt.format(indent, color, prefix, salt.utils.locales.sdecode(msg), endc, suffix)

    def wrap_onspace(self, text):

        '''
        When the text inside the column is longer then the width, will split by space and continue on the next line.'''

        def _truncate(line, word):
            return '{line}{part}{word}'.format(
                        line=line,
                        part=' \n'[(len(line[line.rfind('\n')+1:]) + len(word.split('\n', 1)[0]) >= self.width)],
                        word=word
                    )

        return reduce(_truncate, text.split(' '))

    def prepare_rows(self,
                     rows,
                     indent,
                     has_header):

        '''Prepare rows content to be displayed.'''

        out = []

        def row_wrapper(row):
            new_rows = [
                self.wrapfunc(item).split('\n')
                for item in row
            ]
            rows = []
            for item in map(lambda *args: args, *new_rows):
                if isinstance(item, (tuple, list)):
                    rows.append([substr or '' for substr in item])
                else:
                    rows.append([item])
            return rows

        logical_rows = [
            row_wrapper(row)
            for row in rows
        ]

        columns = map(lambda *args: args, *reduce(operator.add, logical_rows))

        max_widths = [
            max([len(six.text_type(item)) for item in column])
            for column in columns
        ]
        row_separator = self.row_delimiter * (len(self.prefix) + len(self.suffix) + sum(max_widths) +
                                              len(self.delim) * (len(max_widths) - 1))

        justify = self._JUSTIFY_MAP[self.justify.lower()]

        if self.separate_rows:
            out.append(
                self.ustring(
                    indent,
                    self.LIGHT_GRAY,  # pylint: disable=no-member
                    row_separator
                )
            )
        for physical_rows in logical_rows:
{'fraction_non_alphanumeric': 0.10311252992817238, 'fraction_numerical': 0.02226656025538707, 'mean_word_length': 1.6942592990754677, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1040612', 'n_tokens_mistral': 3495, 'n_tokens_neox': 3225, 'n_words': 785}