xml2file.get_user_properties()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 12
nop 1
dl 0
loc 16
rs 9.8
c 0
b 0
f 0
1
#!/usr/bin/env python
2
#
3
# xml2file.py
4
#
5
# Copyright (C) 2019, Takazumi Shirayanagi
6
# This software is released under the new BSD License,
7
# see LICENSE
8
#
9
10
import os
11
import sys
12
import errno
13
import json
14
import codecs
15
import shutil
16
import tempfile
17
import xml.etree.ElementTree as ET
18
19
from argparse import ArgumentParser
20
21
# command line option
22 View Code Duplication
def parse_command_line():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
23
    parser = ArgumentParser()
24
    parser.add_argument(
25
        '-v',
26
        '--version',
27
        action='version',
28
        version=u'%(prog)s version 0.1'
29
    )
30
    parser.add_argument(
31
        '-o',
32
        '--output',
33
        default=None,
34
        help='output file path.'
35
    )
36
    parser.add_argument(
37
        '--no-time',
38
        action='store_true',
39
        help='no output time attribute'
40
    )
41
    parser.add_argument(
42
        '--verbose',
43
        type=int,
44
        default=0,
45
        metavar='LEVEL',
46
        help='log verbose'
47
    )
48
    parser.add_argument(
49
        '--encoding',
50
        default='utf-8',
51
        help='output file encoding.'
52
    )
53
    parser.add_argument(
54
        '--clean',
55
        action='store_true',
56
        help='clean output directory (before)'
57
    )
58
    parser.add_argument(
59
        '--debug',
60
        action='store_true',
61
        help='log debug'
62
    )
63
    parser.add_argument(
64
        'file',
65
        metavar='FILE',
66
        nargs='+',
67
        help='test result xml files'
68
    )
69
    options = parser.parse_args()
70
    return options
71
72
cmdline_options = None
73
74
75
def log(msg):
76
    print(msg)
77
78
79
def logv(lv, msg):
80
    if cmdline_options.verbose >= lv:
81
        print(msg)
82
83
84
def logd(msg):
85
    if cmdline_options.debug:
86
        print(msg)
87
88
89
def loge(msg):
90
    sys.stderr.write(msg + "\n")
91
92
93
def mkdir_p(path):
94
    try:
95
        os.makedirs(path)
96
    except OSError as exc:  # Python >2.5
97
        if exc.errno == errno.EEXIST and os.path.isdir(path):
98
            pass
99
        else:
100
            loge('failed mkdirs: ' + path)
101
            raise
102
103
104
def clean_dir(path):
105
    if os.path.exists(path):
106
        shutil.rmtree(path)
107
108
109
def fopen(path):
110
    dir = os.path.dirname(path)
111
    mkdir_p(dir)
112
    f = codecs.open(path, 'w', cmdline_options.encoding)
113
    return f
114
115
116
def make_rootpath(xml_filename):
117
    root_name = xml_filename
118
    path = os.path.join(cmdline_options.output, root_name)
119
    return path
120
121
122
def make_path(root_path, testsuite, testcase):
123
    suite_name = testsuite.attrib['name'].lstrip('/')
124
    case_name = testcase.attrib['name'].lstrip('/')
125
    ext = '.json'
126
    return os.path.join(os.path.join(root_path, suite_name), case_name + ext)
127
128
129
def get_properties_node(node):
130
    users = {}
131
    for prop in node:
132
        if ('name' in prop.attrib) and ('value' in prop.attrib):
133
            users[prop.attrib['name']] = prop.attrib['value']
134
    return users
135
136
137
def _get_user_properties(node, system_attributes):
138
    users = {}
139
    for a in node.attrib:
140
        if a not in system_attributes:
141
            users[a] = node.attrib[a]
142
    return users
143
144
145
def get_user_properties(node):
146
    system_attributes = {
147
        "testsuites": [
148
            "name", "tests", "failures", "disabled", "skip", "errors", "time", "timestamp", "random_seed"
149
        ],
150
        "testsuite": [
151
            "name", "tests", "failures", "disabled", "skip", "errors", "time", "timestamp", "random_seed"
152
        ],
153
        "testcase": [
154
            "name", "status", "time", "classname", "type_param", "value_param"
155
        ]
156
    }
157
    for k,v in system_attributes.items():
158
        if node.tag == k:
159
            return _get_user_properties(node, v)
160
    return node.attrib
161
162
163
def write_result(f, testsuites_user_attrib, testsuite_user_attrib, testcase):
164
    d = testcase.attrib
165
    if cmdline_options.no_time:
166
        if 'time' in d:
167
            del d['time']
168
    d['testsuites_attrib'] = testsuites_user_attrib
169
    d['testsuite_attrib'] = testsuite_user_attrib
170
    # failure and skipped ...
171
    for child in testcase:
172
        tag = child.tag
173
        if tag not in d:
174
            d[tag] = []
175
        fd = child.attrib
176
        fd['text'] = child.text
177
        d[tag].append(fd)
178
    jt = json.dumps(d, indent=4, ensure_ascii=False)
179
    logd(jt)
180
    f.write(jt)
181
182
183
def opentree(path):
184
    try:
185
        with codecs.open(path, 'r', encoding=cmdline_options.encoding) as f:
186
            return ET.parse(f)
187
    except Exception as e:
188
        loge("error: " + path + ": " + str(e))
189
        xmlp = ET.XMLParser(encoding=cmdline_options.encoding)
190
        return ET.parse(path, xmlp)
191
192
193
def xml2file(path):
194
    basename = os.path.basename(path)
195
    filename = os.path.splitext(basename)[0]
196
    logv(1, basename)
197
198
    root_path = make_rootpath(filename)
199
    clean_dir(root_path)
200
201
    try:
202
        tree = opentree(path)
203
        root = tree.getroot()
204
        testsuites = root
205
206
        testsuites_user_attrib = get_user_properties(testsuites)
207
        for testsuite in testsuites:
208
            logv(2, "  " + testsuite.attrib['name'])
209
            testsuite_user_attrib = get_user_properties(testsuite)
210
            for testcase in testsuite:
211
                if testcase.tag == 'testcase':
212
                    logv(3, "    " + testcase.attrib['name'])
213
                    f = fopen(make_path(root_path, testsuite, testcase))
214
                    write_result(f, testsuites_user_attrib, testsuite_user_attrib, testcase)
215
                    f.close()
216
                elif testcase.tag == 'properties':
217
                    testsuite_user_attrib.update(get_properties_node(testcase))
218
    except Exception as e:
219
        f = fopen(os.path.join(root_path, "parser_error.txt"))
220
        f.write(str(e))
221
        f.close()
222
        raise
223
224
225
def main():
226
    result=True
227
    global cmdline_options
228
    cmdline_options = parse_command_line()
229
    if cmdline_options.output is None:
230
        cmdline_options.output = tempfile.mkdtemp(prefix='xml2file')
231
    logd(sys.getfilesystemencoding())
232
    log("output: " + cmdline_options.output)
233
    if cmdline_options.clean:
234
        clean_dir(cmdline_options.output)
235
    for path in cmdline_options.file:
236
        try:
237
            xml2file(path)
238
        except Exception as e:
239
            loge("error: " + path + ": " + str(e))
240
            result = False
241
    if not result:
242
        exit(1)
243
244
245
if __name__ == '__main__':
246
    main()
247