Completed
Push — master ( 6da3cb...f79971 )
by Fabio
06:44
created

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

Complexity

Conditions 2

Size

Total Lines 7
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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