Passed
Push — master ( db2481...3bd527 )
by Fabio
03:28
created

benedict.dicts.io.io_dict   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 26
eloc 84
dl 0
loc 191
rs 10
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A IODict.to_query_string() 0 7 1
A IODict.from_base64() 0 11 1
A IODict.from_toml() 0 8 1
A IODict.to_yaml() 0 8 1
A IODict.to_xml() 0 8 1
A IODict.from_xml() 0 8 1
A IODict.to_toml() 0 8 1
A IODict._decode() 0 17 4
A IODict.__init__() 0 11 3
A IODict.to_base64() 0 10 1
A IODict.from_json() 0 8 1
A IODict.to_csv() 0 10 1
A IODict.from_query_string() 0 7 1
A IODict.from_csv() 0 10 1
A IODict.from_yaml() 0 8 1
A IODict.to_json() 0 8 1
A IODict._decode_init() 0 11 3
A IODict._encode() 0 7 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) 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
        format = kwargs.pop('format', 'json').lower()
24
        if format in ['b64', 'base64']:
25
            kwargs.setdefault('subformat', 'json')
26
        # decode data-string and initialize with dict data.
27
        try:
28
            d = IODict._decode(s, format, **kwargs)
29
            return d
30
        except ValueError:
31
            raise ValueError('Invalid string data input.')
32
33
    @staticmethod
34
    def _decode(s, format, **kwargs):
35
        try:
36
            content = io_util.read_content(s)
37
            # decode content using the given format
38
            data = io_util.decode(content, format, **kwargs)
39
            if type_util.is_dict(data):
40
                return data
41
            elif type_util.is_list(data):
42
                # force list to dict
43
                return { 'values': data }
44
            else:
45
                raise ValueError(
46
                    'Invalid data type: {}, expected dict or list.'.format(type(data)))
47
        except Exception as e:
48
            raise ValueError(
49
                'Invalid data or url or filepath input argument: {}\n{}'.format(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(IODict._decode(s, '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: https://docs.python.org/3/library/csv.html
76
        Return a new dict instance. A ValueError is raised in case of failure.
77
        """
78
        kwargs['columns'] = columns
79
        kwargs['columns_row'] = columns_row
80
        return cls(IODict._decode(s, 'csv', **kwargs))
81
82
    @classmethod
83
    def from_json(cls, s, **kwargs):
84
        """
85
        Load and decode JSON data from url, filepath or data-string.
86
        Decoder specific options can be passed using kwargs: https://docs.python.org/3/library/json.html
87
        Return a new dict instance. A ValueError is raised in case of failure.
88
        """
89
        return cls(IODict._decode(s, 'json', **kwargs))
90
91
    @classmethod
92
    def from_query_string(cls, s, **kwargs):
93
        """
94
        Load and decode query-string from url, filepath or data-string.
95
        Return a new dict instance. A ValueError is raised in case of failure.
96
        """
97
        return cls(IODict._decode(s, 'query_string', **kwargs))
98
99
    @classmethod
100
    def from_toml(cls, s, **kwargs):
101
        """
102
        Load and decode TOML data from url, filepath or data-string.
103
        Decoder specific options can be passed using kwargs: https://pypi.org/project/toml/
104
        Return a new dict instance. A ValueError is raised in case of failure.
105
        """
106
        return cls(IODict._decode(s, 'toml', **kwargs))
107
108
    @classmethod
109
    def from_xml(cls, s, **kwargs):
110
        """
111
        Load and decode XML data from url, filepath or data-string.
112
        Decoder specific options can be passed using kwargs: https://github.com/martinblech/xmltodict
113
        Return a new dict instance. A ValueError is raised in case of failure.
114
        """
115
        return cls(IODict._decode(s, 'xml', **kwargs))
116
117
    @classmethod
118
    def from_yaml(cls, s, **kwargs):
119
        """
120
        Load and decode YAML data from url, filepath or data-string.
121
        Decoder specific options can be passed using kwargs: https://pyyaml.org/wiki/PyYAMLDocumentation
122
        Return a new dict instance. A ValueError is raised in case of failure.
123
        """
124
        return cls(IODict._decode(s, 'yaml', **kwargs))
125
126
    def to_base64(self, subformat='json', encoding='utf-8', **kwargs):
127
        """
128
        Encode the current dict instance in Base64 format using the given subformat and encoding.
129
        Encoder specific options can be passed using kwargs.
130
        Return the encoded string and optionally save it at the specified 'filepath'.
131
        A ValueError is raised in case of failure.
132
        """
133
        kwargs['subformat'] = subformat
134
        kwargs['encoding'] = encoding
135
        return IODict._encode(self, 'base64', **kwargs)
136
137
    def to_csv(self, key='values', columns=None, columns_row=True, **kwargs):
138
        """
139
        Encode the current dict instance in CSV format.
140
        Encoder specific options can be passed using kwargs: https://docs.python.org/3/library/csv.html
141
        Return the encoded string and optionally save it at the specified 'filepath'.
142
        A ValueError is raised in case of failure.
143
        """
144
        kwargs['columns'] = columns
145
        kwargs['columns_row'] = columns_row
146
        return IODict._encode(self[key], 'csv', **kwargs)
147
148
    def to_json(self, **kwargs):
149
        """
150
        Encode the current dict instance in JSON format.
151
        Encoder specific options can be passed using kwargs: https://docs.python.org/3/library/json.html
152
        Return the encoded string and optionally save it at the specified 'filepath'.
153
        A ValueError is raised in case of failure.
154
        """
155
        return IODict._encode(self, 'json', **kwargs)
156
157
    def to_query_string(self, **kwargs):
158
        """
159
        Encode the current dict instance in query-string format.
160
        Return the encoded string and optionally save it at the specified 'filepath'.
161
        A ValueError is raised in case of failure.
162
        """
163
        return IODict._encode(self, 'query_string', **kwargs)
164
165
    def to_toml(self, **kwargs):
166
        """
167
        Encode the current dict instance in TOML format.
168
        Encoder specific options can be passed using kwargs: https://pypi.org/project/toml/
169
        Return the encoded string and optionally save it at the specified 'filepath'.
170
        A ValueError is raised in case of failure.
171
        """
172
        return IODict._encode(self, 'toml', **kwargs)
173
174
    def to_xml(self, **kwargs):
175
        """
176
        Encode the current dict instance in XML format.
177
        Encoder specific options can be passed using kwargs: https://github.com/martinblech/xmltodict
178
        Return the encoded string and optionally save it at the specified 'filepath'.
179
        A ValueError is raised in case of failure.
180
        """
181
        return IODict._encode(self, 'xml', **kwargs)
182
183
    def to_yaml(self, **kwargs):
184
        """
185
        Encode the current dict instance in YAML format.
186
        Encoder specific options can be passed using kwargs: https://pyyaml.org/wiki/PyYAMLDocumentation
187
        Return the encoded string and optionally save it at the specified 'filepath'.
188
        A ValueError is raised in case of failure.
189
        """
190
        return IODict._encode(self, 'yaml', **kwargs)
191