Completed
Push — master ( 4f4209...7e5a08 )
by Charles
02:37
created

FileDumper.__dump_json()   A

Complexity

Conditions 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 13
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2 1
'''
3
Data dumper to files with several format
4
'''
5 1
import csv
6 1
import json
7
8 1
import xmltodict
9 1
import yaml
10
11 1
import git_app_version.helper.tools as tools
12 1
from git_app_version.helper.pyversion import PY3
13
14 1
try:
15 1
    import ConfigParser as configparser
16 1
except ImportError:
17 1
    import configparser
18
19
20 1
class FileDumper(object):
21
    '''
22
    Main dumper
23
    '''
24
25 1
    def dump(self,
0 ignored issues
show
best-practice introduced by
Too many arguments (9/5)
Loading history...
26
             data=None,
27
             fileformat='json',
28
             target=None,
29
             cwd=None,
30
             namespace='',
31
             csv_delimiter=',',
32
             csv_quote='"',
33
             csv_eol='lf'):
34
        '''
35
        Agnostic main dump function
36
        '''
37
38 1
        target = tools.create_parent_dirs(target, cwd)
39 1
        if fileformat == 'yaml' or fileformat == 'yml':
40 1
            return self.__dump_yaml(data, target, namespace)
41 1
        elif fileformat == 'xml':
42 1
            return self.__dump_xml(data, target, namespace)
43 1
        elif fileformat == 'ini':
44 1
            return self.__dump_ini(data, target, namespace)
45 1
        elif fileformat == 'sh':
46 1
            return self.__dump_sh(data, target)
47 1
        elif fileformat == 'csv':
48 1
            return self.__dump_csv(data, target, delimiter=csv_delimiter,
49
                                   quotechar=csv_quote, eol=csv_eol)
50
        else:
51 1
            return self.__dump_json(data, target, namespace)
52
53 1
    def __create_infos_to_dump(self, infos, namespace=None):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
54
        '''
55
        reorganize data with a namespace if necessary
56
        '''
57
58 1
        to_dump = infos
59 1
        if namespace is not None and namespace != '':
60 1
            namespaces = namespace.split('.')
61 1
            namespaces.reverse()
62 1
            for name in namespaces:
63 1
                to_dump = {name: to_dump}
64
65 1
        return to_dump
66
67 1
    def __dump_sh(self, data, target):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
68
        '''
69
        dump to Shell variables file
70
        '''
71
72 1
        target = target + '.sh'
73
74 1
        with open(target, 'w') as fpt:
75 1
            for key, val in data.items():
76 1
                if not PY3:
77
                    val = tools.encode(tools.flatten(val))
78 1
                fpt.write("{}=\"{}\"\n".format(key, val))
79
80 1
        return target
81
82 1
    def __dump_csv(self, data, target, delimiter=',', quotechar='"', eol='lf'):
0 ignored issues
show
best-practice introduced by
Too many arguments (6/5)
Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
83
        '''
84
        dump to CSV file (comma separated values)
85
        '''
86
87 1
        target = target + '.csv'
88
89 1
        eol = "\r\n" if eol == 'crlf' or eol == "\r\n" else "\n"
90
91 1
        csv.register_dialect('custom', delimiter=str(delimiter),
92
                             lineterminator=str(eol), quotechar=str(quotechar),
93
                             quoting=csv.QUOTE_MINIMAL)
94
95 1
        if PY3:
96 1
            with open(target, 'w', encoding='utf-8') as fpt:
97 1
                writer = csv.writer(fpt, dialect='custom')
98 1
                for key, val in data.items():
99 1
                    writer.writerow((key, val))
100
        else:
101
            with open(target, 'wb') as fpt:
102
                writer = csv.writer(fpt, dialect='custom')
103
                for key, val in data.items():
104
                    val = tools.encode(tools.flatten(val))
105
                    writer.writerow((key, val))
106
107 1
        return target
108
109 1
    def __dump_ini(self, data, target, namespace=None):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
110
        '''
111
        dump to INI file
112
        '''
113
114 1
        target = target + '.ini'
115
116 1
        if namespace is None or namespace == '':
117 1
            namespace = 'app_version'
118
119 1
        ini = configparser.RawConfigParser()
120 1
        ini.add_section(namespace)
121
122 1
        for key, val in data.items():
123 1
            if not PY3:
124
                val = tools.encode(tools.flatten(val))
125
126 1
            ini.set(namespace, key, val)
127
128 1
        with open(target, 'w') as fpt:
129 1
            ini.write(fpt)
130
131 1
        return target
132
133 1
    def __dump_xml(self, data, target, namespace=None):
134
        '''
135
        dump to XML file
136
        '''
137
138 1
        target = target + '.xml'
139 1
        if namespace is None or namespace == '':
140 1
            namespace = 'app_version'
141
142 1
        with open(target, 'w') as fpt:
143 1
            xml = xmltodict.unparse(
144
                self.__create_infos_to_dump(
145
                    data,
146
                    namespace),
147
                encoding='utf-8',
148
                pretty=True,
149
                indent='  ')
150 1
            if not PY3:
151
                xml = xml.encode('utf-8')
152
153 1
            fpt.write(xml)
154
155 1
            return target
156
157 1
    def __dump_json(self, data, target, namespace=None):
158
        '''
159
        dump to JSON file
160
        '''
161
162 1
        target = target + '.json'
163
164 1
        data1 = self.__create_infos_to_dump(data, namespace)
165
166 1
        with open(target, 'w') as fpt:
167 1
            json.dump(data1, fpt, indent=2)
168
169 1
        return target
170
171 1
    def __dump_yaml(self, data, target, namespace=None):
172
        '''
173
        dump to YAML file
174
        '''
175
176 1
        target = target + '.yml'
177
178 1
        with open(target, 'w') as fpt:
179 1
            if not data:
180 1
                fpt.write("---\n")
181
            else:
182 1
                yaml.safe_dump(
183
                    self.__create_infos_to_dump(data, namespace),
184
                    fpt,
185
                    default_flow_style=False,
186
                    explicit_start=True,
187
                    allow_unicode=True,
188
                    # force quoting
189
                    # to prevent abbrev_commit to be read as a float
190
                    default_style='\''
191
                )
192
193
        return target
194