Completed
Push — master ( 5ec698...c095ff )
by P.R.
01:58 queued 41s
created

sdoc.sdoc2.node.TableNode.get_command()   A

Complexity

Conditions 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 7
rs 9.4285
1
"""
2
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9
import re
10
import csv
11
import io
12
from sdoc.sdoc2 import node_store, in_scope, out_scope
13
from sdoc.sdoc2.node.Node import Node
14
15
16
class TableNode(Node):
17
    """
18
    SDoc2 node for table.
19
    """
20
21
    # ------------------------------------------------------------------------------------------------------------------
22
    def __init__(self, options):
23
        """
24
        Object constructor.
25
26
        :param dict[str,str] options: The options of this table.
27
        """
28
        super().__init__('table', options)
29
30
        self.rows = []
31
        """
32
        The table rows.
33
34
        :type: list[list[str]]
35
        """
36
37
        self.column_headers = []
38
        """
39
        The column headers of the table (if any).
40
41
        :type: list[str]
42
        """
43
44
        self.alignments = []
45
        """
46
        The text alignments in the table columns.
47
48
        :type: list[str|None]
49
        """
50
51
    # ------------------------------------------------------------------------------------------------------------------
52
    def get_command(self):
53
        """
54
        Returns the command of this node, i.e. table.
55
56
        :rtype: str
57
        """
58
        return 'table'
59
60
    # ------------------------------------------------------------------------------------------------------------------
61
    def is_block_command(self):
62
        """
63
        Returns True.
64
65
        :rtype: bool
66
        """
67
        return True
68
69
    # ------------------------------------------------------------------------------------------------------------------
70
    def is_inline_command(self):
71
        """
72
        Returns False.
73
74
        :rtype: bool
75
        """
76
        return False
77
78
    # ------------------------------------------------------------------------------------------------------------------
79
    def prepare_content_tree(self):
80
        """
81
        Prepares this node for further processing.
82
        """
83
        for node_id in self.child_nodes:
84
            node = in_scope(node_id)
85
86
            self.extract_table(node)
87
88
            node.prepare_content_tree()
89
90
            out_scope(node)
91
92
    # ------------------------------------------------------------------------------------------------------------------
93
    def extract_table(self, node):
94
        """
95
        Extract the table data from a TextNode.
96
97
        :param sdoc.sdoc2.node.Node.Node node: The node which may be interpreted as table.
98
        """
99
        temp_table_items = node.argument.split('\n')
100
101
        # Remove empty rows.
102
        while '' in temp_table_items:
103
            temp_table_items.remove('')
104
105
        # Derive table data.
106
        rows = []
107
        for item in temp_table_items:
108
            string = io.StringIO(item)
109
            reader = csv.reader(string, delimiter='|')
110
            for line in reader:
111
                row = line
112
                row = self.prune_whitespace(row)
113
                rows.append(row)
114
115
        if self.has_header(rows):
116
            self.column_headers = rows[0]
117
            self.rows = rows[2:]
118
            self.alignments = self.get_column_alignments(rows[1])
119
        else:
120
            self.rows = rows
121
122
    # ------------------------------------------------------------------------------------------------------------------
123
    @staticmethod
124
    def has_header(row):
125
        """
126
        Returns True if the table has a table header.
127
128
        :param list[str] row: The second row of the table.
129
130
        :rtype: bool
131
        """
132
        is_header = True
133
        for align in row[1]:
134
            header_part = re.findall(':?---+-*:?', align)
135
            if not header_part:
136
                is_header = False
137
                break
138
139
        return is_header
140
141
    # ------------------------------------------------------------------------------------------------------------------
142
    @staticmethod
143
    def get_column_alignments(row):
144
        """
145
        Sets alignments on table columns.
146
147
        :param list[str] row: The row with hyphens for creating column headers.
148
149
        :rtype: list[str]
150
        """
151
        alignments = []
152
        for hyphens in row:
153
            hyphens = hyphens.strip()
154
            if hyphens.startswith(':') and hyphens.endswith(':'):
155
                alignments.append('center')
156
            elif hyphens.startswith(':'):
157
                alignments.append('left')
158
            elif hyphens.endswith(':'):
159
                alignments.append('right')
160
            else:
161
                alignments.append('')
162
163
        return alignments
164
165
    # ------------------------------------------------------------------------------------------------------------------
166
    @staticmethod
167
    def prune_whitespace(row):
168
        """
169
        Strips whitespaces from the text of an each cell.
170
171
        :param list[str] row: The row with text of an each cell.
172
        :rtype: list[str]
173
        """
174
        clear_row = []
175
        for item in row:
176
            clear_text = item.strip()
177
            clear_text = re.sub('\s+', ' ', clear_text)
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
178
            clear_row.append(clear_text)
179
180
        return clear_row
181
182
# ----------------------------------------------------------------------------------------------------------------------
183
node_store.register_block_command('table', TableNode)
184