Completed
Push — master ( 21567f...6fc5da )
by Kolen
01:12
created

parse_table_options()   C

Complexity

Conditions 7

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 14
Bugs 0 Features 1
Metric Value
cc 7
c 14
b 0
f 1
dl 0
loc 26
rs 5.5
1
#!/usr/bin/env python3
2
3
r"""
4
Panflute filter to convert any native pandoc tables into the CSV table format used by pantable:
5
6
- in code-block with class table
7
- metadata in YAML
8
- table in CSV
9
10
e.g.
11
12
~~~markdown
13
+--------+---------------------+--------------------------+
14
| First  | defaulted to be     | can be disabled          |
15
| row    | header row          |                          |
16
+========+=====================+==========================+
17
| 1      | cell can contain    | It can be aribrary block |
18
|        | **markdown**        | element:                 |
19
|        |                     |                          |
20
|        |                     | -   following standard   |
21
|        |                     |     markdown syntax      |
22
|        |                     | -   like this            |
23
+--------+---------------------+--------------------------+
24
| 2      | Any markdown        | $$E = mc^2$$             |
25
|        | syntax, e.g.        |                          |
26
+--------+---------------------+--------------------------+
27
28
: *Awesome* **Markdown** Table
29
~~~
30
31
becomes
32
33
~~~markdown
34
``` {.table}
35
---
36
alignment: DDD
37
caption: '*Awesome* **Markdown** Table'
38
header: true
39
markdown: true
40
table-width: 0.8055555555555556
41
width: [0.125, 0.3055555555555556, 0.375]
42
---
43
First row,defaulted to be header row,can be disabled
44
1,cell can contain **markdown**,"It can be aribrary block element:
45
46
-   following standard markdown syntax
47
-   like this
48
"
49
2,"Any markdown syntax, e.g.",$$E = mc^2$$
50
```
51
~~~
52
"""
53
54
import panflute
55
import io
56
import csv
57
import yaml
58
59
60
def ast2markdown(*ast):
61
    """
62
    convert a panflute ast into markdown
63
    """
64
    return panflute.convert_text(ast, input_format='panflute', output_format='markdown')
65
66
67
def get_table_options(elem):
68
    """
69
    parse the content of Table in ast and returns a dictionary of options
70
    """
71
    options = {}
72
    options['caption'] = elem.caption
73
    options['alignment'] = elem.alignment
74
    options['width'] = elem.width
75
    options['header'] = elem.header
76
    options['markdown'] = True
77
    return options
78
79
80
def parse_table_options(options):
81
    """
82
    parse the options
83
    """
84
    # caption: panflute ast to markdown
85
    if options['caption']:
86
        options['caption'] = ast2markdown(panflute.Para(*options['caption']))
87
    else:
88
        del options['caption']
89
    # parse alignment
90
    parsed_alignment = []
91
    for alignment in options['alignment']:
92
        if alignment == "AlignLeft":
93
            parsed_alignment.append("L")
94
        elif alignment == "AlignCenter":
95
            parsed_alignment.append("C")
96
        elif alignment == "AlignRight":
97
            parsed_alignment.append("R")
98
        elif alignment == "AlignDefault":
99
            parsed_alignment.append("D")
100
    options['alignment'] = "".join(parsed_alignment)
101
    # table-width from width
102
    options['table-width'] = sum(options['width'])
103
    # header: False if empty header row, else True
104
    options['header'] = bool(panflute.stringify(options['header']))
105
    return
106
107
108
def get_table_body(options, elem):
109
    """
110
    from elem, get full table body including header row if any
111
    """
112
    table_body = elem.content
113
    if options['header']:
114
        table_body.insert(0, elem.header)
115
    return table_body
116
117
118
def Table2list(Table):
119
    """
120
    convert a pandoc table into a 2D list
121
    """
122
    return [[ast2markdown(*cell.content) for cell in row.content] for row in Table]
123
124
125
def list2csv(table_list):
126
    with io.StringIO() as file:
127
        writer = csv.writer(file)
128
        writer.writerows(table_list)
129
        csv_table = file.getvalue()
130
    return csv_table
131
132
133
def options2yaml(options):
134
    return yaml.dump(options)
135
136
137
def table2csv(elem, doc):
138
    """
139
    find Table element and return a csv table in code-block with class "table"
140
    """
141
    if isinstance(elem, panflute.Table):
142
        # obtain options from Table
143
        options = get_table_options(elem)
144
        parse_table_options(options)
145
        # table in AST
146
        table_body = get_table_body(options, elem)
147
        # table in list
148
        table_list = Table2list(table_body)
149
        # table in CSV
150
        csv_table = list2csv(table_list)
151
        # option in YAML
152
        yaml_metadata = options2yaml(options)
153
        code_block = "---\n" + yaml_metadata + "---\n" + csv_table
154
        return panflute.CodeBlock(code_block, classes=["table"])
155
    return None
156
157
158
def main(_=None):
159
    """
160
    Any native pandoc tables will be converted into the CSV table format used by pantable:
161
162
    - in code-block with class table
163
    - metadata in YAML
164
    - table in CSV
165
    """
166
    panflute.run_filter(table2csv)
167
168
if __name__ == '__main__':
169
    main()
170