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