Passed
Push — master ( 769cd8...7d2af2 )
by Fabio
01:16
created

benedict.dicts.io.io_dict.IODict._decode_init()   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
nop 2
1
# -*- coding: utf-8 -*-
2
3
from benedict.dicts.io import io_util
4
from benedict.utils import type_util
5
6
7
class IODict(dict):
8
9
    def __init__(self, *args, **kwargs):
10
        """
11
        Constructs a new instance.
12
        """
13
        # if first argument is data-string, url or filepath try to decode it.
14
        # use 'format' kwarg to specify the decoder to use, default 'json'.
15
        if len(args) == 1 and type_util.is_string(args[0]):
16
            d = IODict._decode_init(args[0], **kwargs)
17
            super(IODict, self).__init__(d)
18
            return
19
        super(IODict, self).__init__(*args, **kwargs)
20
21
    @staticmethod
22
    def _decode_init(s, **kwargs):
23
        autodetected_format = io_util.autodetect_format(s)
24
        default_format = autodetected_format or 'json'
25
        format = kwargs.pop('format', default_format).lower()
26
        if format in ['b64', 'base64']:
27
            kwargs.setdefault('subformat', 'json')
28
        # decode data-string and initialize with dict data.
29
        return IODict._decode(s, format, **kwargs)
30
31
    @staticmethod
32
    def _decode(s, format, **kwargs):
33
        try:
34
            content = io_util.read_content(s)
35
            # decode content using the given format
36
            data = io_util.decode(content, format, **kwargs)
37
            if type_util.is_dict(data):
38
                return data
39
            elif type_util.is_list(data):
40
                # force list to dict
41
                return {'values': data}
42
            else:
43
                raise ValueError(
44
                    'Invalid data type: {}, expected dict or list.'.format(
45
                        type(data)))
46
        except Exception as e:
47
            raise ValueError(
48
                'Invalid data or url or filepath argument: {}\n{}'.format(
49
                    s, e))
50
51
    @staticmethod
52
    def _encode(d, format, **kwargs):
53
        filepath = kwargs.pop('filepath', None)
54
        s = io_util.encode(d, format, **kwargs)
55
        if filepath:
56
            io_util.write_file(filepath, s)
57
        return s
58
59
    @classmethod
60
    def from_base64(cls, s, subformat='json', encoding='utf-8', **kwargs):
61
        """
62
        Load and decode Base64 data from url, filepath or data-string.
63
        Data is decoded according to subformat and encoding.
64
        Decoder specific options can be passed using kwargs.
65
        Return a new dict instance. A ValueError is raised in case of failure.
66
        """
67
        kwargs['subformat'] = subformat
68
        kwargs['encoding'] = encoding
69
        return cls(s, format='base64', **kwargs)
70
71
    @classmethod
72
    def from_csv(cls, s, columns=None, columns_row=True, **kwargs):
73
        """
74
        Load and decode CSV data from url, filepath or data-string.
75
        Decoder specific options can be passed using kwargs:
76
        https://docs.python.org/3/library/csv.html
77
        Return a new dict instance. A ValueError is raised in case of failure.
78
        """
79
        kwargs['columns'] = columns
80
        kwargs['columns_row'] = columns_row
81
        return cls(s, format='csv', **kwargs)
82
83
    @classmethod
84
    def from_json(cls, s, **kwargs):
85
        """
86
        Load and decode JSON data from url, filepath or data-string.
87
        Decoder specific options can be passed using kwargs:
88
        https://docs.python.org/3/library/json.html
89
        Return a new dict instance. A ValueError is raised in case of failure.
90
        """
91
        return cls(s, format='json', **kwargs)
92
93
    @classmethod
94
    def from_pickle(cls, s, **kwargs):
95
        """
96
        Load and decode a pickle encoded in Base64 format data from url, filepath or data-string.
97
        Decoder specific options can be passed using kwargs:
98
        https://docs.python.org/3/library/pickle.html
99
        Return a new dict instance. A ValueError is raised in case of failure.
100
        """
101
        return cls(s, format='pickle', **kwargs)
102
103
    @classmethod
104
    def from_plist(cls, s, **kwargs):
105
        """
106
        Load and decode p-list data from url, filepath or data-string.
107
        Decoder specific options can be passed using kwargs:
108
        https://docs.python.org/3/library/plistlib.html
109
        Return a new dict instance. A ValueError is raised in case of failure.
110
        """
111
        return cls(s, format='plist', **kwargs)
112
113
    @classmethod
114
    def from_query_string(cls, s, **kwargs):
115
        """
116
        Load and decode query-string from url, filepath or data-string.
117
        Return a new dict instance. A ValueError is raised in case of failure.
118
        """
119
        return cls(s, format='query_string', **kwargs)
120
121
    @classmethod
122
    def from_toml(cls, s, **kwargs):
123
        """
124
        Load and decode TOML data from url, filepath or data-string.
125
        Decoder specific options can be passed using kwargs:
126
        https://pypi.org/project/toml/
127
        Return a new dict instance. A ValueError is raised in case of failure.
128
        """
129
        return cls(s, format='toml', **kwargs)
130
131
    @classmethod
132
    def from_xml(cls, s, **kwargs):
133
        """
134
        Load and decode XML data from url, filepath or data-string.
135
        Decoder specific options can be passed using kwargs:
136
        https://github.com/martinblech/xmltodict
137
        Return a new dict instance. A ValueError is raised in case of failure.
138
        """
139
        return cls(s, format='xml', **kwargs)
140
141
    @classmethod
142
    def from_yaml(cls, s, **kwargs):
143
        """
144
        Load and decode YAML data from url, filepath or data-string.
145
        Decoder specific options can be passed using kwargs:
146
        https://pyyaml.org/wiki/PyYAMLDocumentation
147
        Return a new dict instance. A ValueError is raised in case of failure.
148
        """
149
        return cls(s, format='yaml', **kwargs)
150
151
    def to_base64(self, subformat='json', encoding='utf-8', **kwargs):
152
        """
153
        Encode the current dict instance in Base64 format
154
        using the given subformat and encoding.
155
        Encoder specific options can be passed using kwargs.
156
        Return the encoded string and optionally save it at 'filepath'.
157
        A ValueError is raised in case of failure.
158
        """
159
        kwargs['subformat'] = subformat
160
        kwargs['encoding'] = encoding
161
        return self._encode(self, 'base64', **kwargs)
162
163
    def to_csv(self, key='values', columns=None, columns_row=True, **kwargs):
164
        """
165
        Encode the current dict instance in CSV format.
166
        Encoder specific options can be passed using kwargs:
167
        https://docs.python.org/3/library/csv.html
168
        Return the encoded string and optionally save it at 'filepath'.
169
        A ValueError is raised in case of failure.
170
        """
171
        kwargs['columns'] = columns
172
        kwargs['columns_row'] = columns_row
173
        return self._encode(self[key], 'csv', **kwargs)
174
175
    def to_json(self, **kwargs):
176
        """
177
        Encode the current dict instance in JSON format.
178
        Encoder specific options can be passed using kwargs:
179
        https://docs.python.org/3/library/json.html
180
        Return the encoded string and optionally save it at 'filepath'.
181
        A ValueError is raised in case of failure.
182
        """
183
        return self._encode(self, 'json', **kwargs)
184
185
    def to_pickle(self, **kwargs):
186
        """
187
        Encode the current dict instance as pickle (encoded in Base64).
188
        The pickle protocol used by default is 2.
189
        Encoder specific options can be passed using kwargs:
190
        https://docs.python.org/3/library/pickle.html
191
        Return the encoded string and optionally save it at 'filepath'.
192
        A ValueError is raised in case of failure.
193
        """
194
        return self._encode(self, 'pickle', **kwargs)
195
196
    def to_plist(self, **kwargs):
197
        """
198
        Encode the current dict instance as p-list.
199
        Encoder specific options can be passed using kwargs:
200
        https://docs.python.org/3/library/plistlib.html
201
        Return the encoded string and optionally save it at 'filepath'.
202
        A ValueError is raised in case of failure.
203
        """
204
        return self._encode(self, 'plist', **kwargs)
205
206
    def to_query_string(self, **kwargs):
207
        """
208
        Encode the current dict instance in query-string format.
209
        Return the encoded string and optionally save it at 'filepath'.
210
        A ValueError is raised in case of failure.
211
        """
212
        return self._encode(self, 'query_string', **kwargs)
213
214
    def to_toml(self, **kwargs):
215
        """
216
        Encode the current dict instance in TOML format.
217
        Encoder specific options can be passed using kwargs:
218
        https://pypi.org/project/toml/
219
        Return the encoded string and optionally save it at 'filepath'.
220
        A ValueError is raised in case of failure.
221
        """
222
        return self._encode(self, 'toml', **kwargs)
223
224
    def to_xml(self, **kwargs):
225
        """
226
        Encode the current dict instance in XML format.
227
        Encoder specific options can be passed using kwargs:
228
        https://github.com/martinblech/xmltodict
229
        Return the encoded string and optionally save it at 'filepath'.
230
        A ValueError is raised in case of failure.
231
        """
232
        return self._encode(self, 'xml', **kwargs)
233
234
    def to_yaml(self, **kwargs):
235
        """
236
        Encode the current dict instance in YAML format.
237
        Encoder specific options can be passed using kwargs:
238
        https://pyyaml.org/wiki/PyYAMLDocumentation
239
        Return the encoded string and optionally save it at 'filepath'.
240
        A ValueError is raised in case of failure.
241
        """
242
        return self._encode(self, 'yaml', **kwargs)
243