satcfdi.models.py2html._get_column_headers()   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 5
nop 1
dl 0
loc 11
ccs 5
cts 5
cp 1
crap 4
rs 10
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
"""
3
HTML Converter
4
"""
5 1
from collections.abc import Mapping, Sequence
6 1
from html import escape as html_escape
7
8
9 1
def dumps(obj, clubbing=True, escape=True, translate_keys=None, default=str):
10
    """
11
        Convert object to HTML Table format
12
    """
13 1
    encoder = PY2HTMLEncoder(clubbing, escape, translate_keys, default)
14 1
    return "".join(encoder.encode(obj))
15
16
17 1
def _get_column_headers(py_input):
18
    """
19
        This method is required to implement clubbing.
20
        It tries to come up with column headers for your input
21
    """
22 1
    if py_input and isinstance(py_input, Sequence):
23 1
        if isinstance(py_input[0], Mapping):
24
            # use a dict to maintain consisten order
25 1
            return {k: None for r in py_input for k in r.keys()}
26
27 1
    return None
28
29
30 1
class PY2HTMLEncoder:
31 1
    def __init__(self, clubbing=True, escape=True, translate_keys=None, default=str):
32 1
        self.clubbing = clubbing
33 1
        self.escape = escape
34 1
        self.translate_keys = translate_keys
35 1
        self.default = default
36
37 1
    def encode(self, input):
38
        """
39
            Dispatch JSON input according to the outermost type and process it
40
            to generate the super awesome HTML format.
41
            We try to adhere to duck typing such that users can just pass all kinds
42
            of funky objects to py2html that *behave* like dicts and lists and other
43
            basic JSON types.
44
        """
45 1
        if isinstance(input, str):
46 1
            if self.escape:
47 1
                yield html_escape(input)
48 1
                return
49
            else:
50
                yield input
51
                return
52 1
        if isinstance(input, Mapping):
53 1
            yield from self.convert_object(input)
54 1
            return
55
56 1
        if isinstance(input, Sequence):
57 1
            yield from self.convert_list(input)
58 1
            return
59
60 1
        if self.escape:
61 1
            yield html_escape(str(self.default(input)))
62 1
            return
63
        else:
64
            yield str(self.default(input))
65
            return
66
67 1
    def convert_list(self, list_input):
68
        """
69
            Iterate over the JSON list and process it
70
            to generate either an HTML table or a HTML list, depending on what's inside.
71
            If suppose some key has array of objects and all the keys are same,
72
            instead of creating a new row for each such entry,
73
            club such values, thus it makes more sense and more readable table.
74
75
            @example:
76
                pyObject = {
77
                    "sampleData": [
78
                        {"a":1, "b":2, "c":3},
79
                        {"a":5, "b":6, "c":7}
80
                    ]
81
                }
82
                OUTPUT:
83
                _____________________________
84
                |               |   |   |   |
85
                |               | a | c | b |
86
                |   sampleData  |---|---|---|
87
                |               | 1 | 3 | 2 |
88
                |               | 5 | 7 | 6 |
89
                -----------------------------
90
91
            @contributed by: @muellermichel
92
        """
93 1
        if not list_input:
94
            return
95
96 1
        if self.clubbing:
97 1
            column_headers = _get_column_headers(list_input)
98
99 1
            if column_headers is not None:
100 1
                yield "<table>"
101 1
                yield '<thead>'
102 1
                yield '<tr><th>' + '</th><th>'.join(self.translate_keys(k) for k in column_headers) + '</th></tr>'
103 1
                yield '</thead><tbody>'
104 1
                for list_entry in list_input:
105 1
                    yield '<tr>'
106 1
                    for column_header in column_headers:
107 1
                        yield "<td>"
108 1
                        yield from self.encode(list_entry.get(column_header, ""))
109 1
                        yield '</td>'
110 1
                    yield '</tr>'
111 1
                yield '</tbody></table>'
112 1
                return
113
114
        # so you don't want or need clubbing eh? This makes @muellermichel very sad... ;(
115
        # alright, let's fall back to a basic list here...
116 1
        yield '<ul>'
117 1
        for child in list_input:
118 1
            yield "<li>"
119 1
            yield from self.encode(child)
120 1
            yield "</li>"
121 1
        yield '</ul>'
122
123 1
    def convert_object(self, dict_input):
124
        """
125
            Iterate over the JSON object and process it
126
            to generate the super awesome HTML Table format
127
        """
128 1
        if not dict_input:
129
            return
130
131 1
        yield "<table>"
132 1
        for k, v in dict_input.items():
133 1
            if v is not None:
134 1
                yield "<tr><td class='htd'>"
135 1
                yield from self.encode(self.translate_keys(k) + ":")
136 1
                yield "</td><td>"
137 1
                yield from self.encode(v)
138 1
                yield "</td></tr>"
139
        yield '</table>'
140