Passed
Push — master ( d636b2...ee6986 )
by Fabio
06:00
created

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

Complexity

Conditions 1

Size

Total Lines 23
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nop 7
dl 0
loc 23
rs 9.95
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
3
from benedict.dicts.base import BaseDict
4
from benedict.dicts.io import io_util
5
from benedict.utils import type_util
6
7
8
class IODict(BaseDict):
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
        # decode data-string and initialize with dict data.
27
        return IODict._decode(s, format, **kwargs)
28
29
    @staticmethod
30
    def _decode(s, format, **kwargs):
31
        data = None
32
        try:
33
            data = io_util.decode(s, format, **kwargs)
34
        except Exception as e:
35
            raise ValueError(f"Invalid data or url or filepath argument: {s}\n{e}")
36
        # if possible return data as dict, otherwise raise exception
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(f"Invalid data type: {type(data)}, expected dict or list.")
44
45
    @staticmethod
46
    def _encode(d, format, **kwargs):
47
        filepath = kwargs.pop("filepath", None)
48
        s = io_util.encode(d, format, **kwargs)
49
        if filepath:
50
            io_util.write_file(filepath, s)
51
        return s
52
53
    @classmethod
54
    def from_base64(cls, s, subformat="json", encoding="utf-8", **kwargs):
55
        """
56
        Load and decode Base64 data from url, filepath or data-string.
57
        Data is decoded according to subformat and encoding.
58
        Decoder specific options can be passed using kwargs.
59
        Return a new dict instance. A ValueError is raised in case of failure.
60
        """
61
        kwargs["subformat"] = subformat
62
        kwargs["encoding"] = encoding
63
        return cls(s, format="base64", **kwargs)
64
65
    @classmethod
66
    def from_csv(cls, s, columns=None, columns_row=True, **kwargs):
67
        """
68
        Load and decode CSV data from url, filepath or data-string.
69
        Decoder specific options can be passed using kwargs:
70
        https://docs.python.org/3/library/csv.html
71
        Return a new dict instance. A ValueError is raised in case of failure.
72
        """
73
        kwargs["columns"] = columns
74
        kwargs["columns_row"] = columns_row
75
        return cls(s, format="csv", **kwargs)
76
77
    @classmethod
78
    def from_ini(cls, s, **kwargs):
79
        """
80
        Load and decode INI data from url, filepath or data-string.
81
        Decoder specific options can be passed using kwargs:
82
        https://docs.python.org/3/library/configparser.html
83
        Return a new dict instance. A ValueError is raised in case of failure.
84
        """
85
        return cls(s, format="ini", **kwargs)
86
87
    @classmethod
88
    def from_json(cls, s, **kwargs):
89
        """
90
        Load and decode JSON data from url, filepath or data-string.
91
        Decoder specific options can be passed using kwargs:
92
        https://docs.python.org/3/library/json.html
93
        Return a new dict instance. A ValueError is raised in case of failure.
94
        """
95
        return cls(s, format="json", **kwargs)
96
97
    @classmethod
98
    def from_pickle(cls, s, **kwargs):
99
        """
100
        Load and decode a pickle encoded in Base64 format data from url, filepath or data-string.
101
        Decoder specific options can be passed using kwargs:
102
        https://docs.python.org/3/library/pickle.html
103
        Return a new dict instance. A ValueError is raised in case of failure.
104
        """
105
        return cls(s, format="pickle", **kwargs)
106
107
    @classmethod
108
    def from_plist(cls, s, **kwargs):
109
        """
110
        Load and decode p-list data from url, filepath or data-string.
111
        Decoder specific options can be passed using kwargs:
112
        https://docs.python.org/3/library/plistlib.html
113
        Return a new dict instance. A ValueError is raised in case of failure.
114
        """
115
        return cls(s, format="plist", **kwargs)
116
117
    @classmethod
118
    def from_query_string(cls, s, **kwargs):
119
        """
120
        Load and decode query-string from url, filepath or data-string.
121
        Return a new dict instance. A ValueError is raised in case of failure.
122
        """
123
        return cls(s, format="query_string", **kwargs)
124
125
    @classmethod
126
    def from_toml(cls, s, **kwargs):
127
        """
128
        Load and decode TOML data from url, filepath or data-string.
129
        Decoder specific options can be passed using kwargs:
130
        https://pypi.org/project/toml/
131
        Return a new dict instance. A ValueError is raised in case of failure.
132
        """
133
        return cls(s, format="toml", **kwargs)
134
135
    @classmethod
136
    def from_xls(cls, s, sheet=0, columns=None, columns_row=True, **kwargs):
137
        """
138
        Load and decode XLS files (".xls", ".xlsx", ".xlsm") from url, filepath or data-string.
139
        Decoder specific options can be passed using kwargs:
140
        - https://openpyxl.readthedocs.io/ (for .xlsx and .xlsm files)
141
        - https://pypi.org/project/xlrd/ (for .xls files)
142
        Return a new dict instance. A ValueError is raised in case of failure.
143
        """
144
        kwargs["sheet"] = sheet
145
        kwargs["columns"] = columns
146
        kwargs["columns_row"] = columns_row
147
        return cls(s, format="xls", **kwargs)
148
149
    @classmethod
150
    def from_xml(cls, s, **kwargs):
151
        """
152
        Load and decode XML data from url, filepath or data-string.
153
        Decoder specific options can be passed using kwargs:
154
        https://github.com/martinblech/xmltodict
155
        Return a new dict instance. A ValueError is raised in case of failure.
156
        """
157
        return cls(s, format="xml", **kwargs)
158
159
    @classmethod
160
    def from_yaml(cls, s, **kwargs):
161
        """
162
        Load and decode YAML data from url, filepath or data-string.
163
        Decoder specific options can be passed using kwargs:
164
        https://pyyaml.org/wiki/PyYAMLDocumentation
165
        Return a new dict instance. A ValueError is raised in case of failure.
166
        """
167
        return cls(s, format="yaml", **kwargs)
168
169
    def to_base64(self, subformat="json", encoding="utf-8", **kwargs):
170
        """
171
        Encode the current dict instance in Base64 format
172
        using the given subformat and encoding.
173
        Encoder specific options can be passed using kwargs.
174
        Return the encoded string and optionally save it at 'filepath'.
175
        A ValueError is raised in case of failure.
176
        """
177
        kwargs["subformat"] = subformat
178
        kwargs["encoding"] = encoding
179
        return self._encode(self.dict(), "base64", **kwargs)
180
181
    def to_csv(self, key="values", columns=None, columns_row=True, **kwargs):
182
        """
183
        Encode a list of dicts in the current dict instance in CSV format.
184
        Encoder specific options can be passed using kwargs:
185
        https://docs.python.org/3/library/csv.html
186
        Return the encoded string and optionally save it at 'filepath'.
187
        A ValueError is raised in case of failure.
188
        """
189
        kwargs["columns"] = columns
190
        kwargs["columns_row"] = columns_row
191
        return self._encode(self.dict()[key], "csv", **kwargs)
192
193
    def to_ini(self, **kwargs):
194
        """
195
        Encode the current dict instance in INI format.
196
        Encoder specific options can be passed using kwargs:
197
        https://docs.python.org/3/library/configparser.html
198
        Return the encoded string and optionally save it at 'filepath'.
199
        A ValueError is raised in case of failure.
200
        """
201
        return self._encode(self.dict(), "ini", **kwargs)
202
203
    def to_json(self, **kwargs):
204
        """
205
        Encode the current dict instance in JSON format.
206
        Encoder specific options can be passed using kwargs:
207
        https://docs.python.org/3/library/json.html
208
        Return the encoded string and optionally save it at 'filepath'.
209
        A ValueError is raised in case of failure.
210
        """
211
        return self._encode(self.dict(), "json", **kwargs)
212
213
    def to_pickle(self, **kwargs):
214
        """
215
        Encode the current dict instance as pickle (encoded in Base64).
216
        The pickle protocol used by default is 2.
217
        Encoder specific options can be passed using kwargs:
218
        https://docs.python.org/3/library/pickle.html
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.dict(), "pickle", **kwargs)
223
224
    def to_plist(self, **kwargs):
225
        """
226
        Encode the current dict instance as p-list.
227
        Encoder specific options can be passed using kwargs:
228
        https://docs.python.org/3/library/plistlib.html
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.dict(), "plist", **kwargs)
233
234
    def to_query_string(self, **kwargs):
235
        """
236
        Encode the current dict instance in query-string format.
237
        Return the encoded string and optionally save it at 'filepath'.
238
        A ValueError is raised in case of failure.
239
        """
240
        return self._encode(self.dict(), "query_string", **kwargs)
241
242
    def to_toml(self, **kwargs):
243
        """
244
        Encode the current dict instance in TOML format.
245
        Encoder specific options can be passed using kwargs:
246
        https://pypi.org/project/toml/
247
        Return the encoded string and optionally save it at 'filepath'.
248
        A ValueError is raised in case of failure.
249
        """
250
        return self._encode(self.dict(), "toml", **kwargs)
251
252
    def to_xml(self, **kwargs):
253
        """
254
        Encode the current dict instance in XML format.
255
        Encoder specific options can be passed using kwargs:
256
        https://github.com/martinblech/xmltodict
257
        Return the encoded string and optionally save it at 'filepath'.
258
        A ValueError is raised in case of failure.
259
        """
260
        return self._encode(self.dict(), "xml", **kwargs)
261
262
    def to_xls(
263
        self,
264
        key="values",
265
        sheet=0,
266
        columns=None,
267
        columns_row=True,
268
        format="xlsx",
269
        **kwargs,
270
    ):
271
        """
272
        Encode a list of dicts in the current dict instance in XLS format.
273
        Encoder specific options can be passed using kwargs:
274
        - https://openpyxl.readthedocs.io/ (for .xlsx and .xlsm files)
275
        - https://pypi.org/project/xlrd/ (for .xls files)
276
        Return the encoded string and optionally save it at 'filepath'.
277
        A ValueError is raised in case of failure.
278
        """
279
        # kwargs["sheet"] = sheet
280
        # kwargs["columns"] = columns
281
        # kwargs["columns_row"] = columns_row
282
        # kwargs["format"] = format
283
        # return self._encode(self.dict()[key], "xls", **kwargs)
284
        raise NotImplementedError
285
286
    def to_yaml(self, **kwargs):
287
        """
288
        Encode the current dict instance in YAML format.
289
        Encoder specific options can be passed using kwargs:
290
        https://pyyaml.org/wiki/PyYAMLDocumentation
291
        Return the encoded string and optionally save it at 'filepath'.
292
        A ValueError is raised in case of failure.
293
        """
294
        return self._encode(self.dict(), "yaml", **kwargs)
295