191 lines
7.7 KiB
Python
191 lines
7.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from benedict.utils import io_util, type_util
|
|
|
|
|
|
class IODict(dict):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""
|
|
Constructs a new instance.
|
|
"""
|
|
# if first argument is data-string, url or filepath try to decode it.
|
|
# use 'format' kwarg to specify the decoder to use, default 'json'.
|
|
if len(args) and type_util.is_string(args[0]):
|
|
d = IODict._decode_init(args[0], *args, **kwargs)
|
|
super(IODict, self).__init__(d)
|
|
return
|
|
super(IODict, self).__init__(*args, **kwargs)
|
|
|
|
@staticmethod
|
|
def _decode_init(s, *args, **kwargs):
|
|
format = kwargs.pop('format', 'json').lower()
|
|
if format in ['b64', 'base64']:
|
|
kwargs.setdefault('subformat', 'json')
|
|
# decode data-string and initialize with dict data.
|
|
d = IODict._decode(s, format, **kwargs)
|
|
if type_util.is_dict(d):
|
|
return d
|
|
raise ValueError('Invalid string data input.')
|
|
|
|
@staticmethod
|
|
def _decode(s, format, **kwargs):
|
|
d = None
|
|
try:
|
|
content = io_util.read_content(s)
|
|
# decode content using the given format
|
|
data = io_util.decode(content, format, **kwargs)
|
|
if type_util.is_dict(data):
|
|
d = data
|
|
elif type_util.is_list(data):
|
|
# force list to dict
|
|
d = { 'values': data }
|
|
else:
|
|
raise ValueError(
|
|
'Invalid data type: {}, expected dict or list.'.format(type(data)))
|
|
except Exception as e:
|
|
raise ValueError(
|
|
'Invalid data or url or filepath input argument: {}\n{}'.format(s, e))
|
|
return d
|
|
|
|
@staticmethod
|
|
def _encode(d, format, **kwargs):
|
|
filepath = kwargs.pop('filepath', None)
|
|
s = io_util.encode(d, format, **kwargs)
|
|
if filepath:
|
|
io_util.write_file(filepath, s)
|
|
return s
|
|
|
|
@classmethod
|
|
def from_base64(cls, s, subformat='json', encoding='utf-8', **kwargs):
|
|
"""
|
|
Load and decode Base64 data from url, filepath or data-string.
|
|
Data is decoded according to subformat and encoding.
|
|
Decoder specific options can be passed using kwargs.
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
kwargs['subformat'] = subformat
|
|
kwargs['encoding'] = encoding
|
|
return cls(IODict._decode(s, 'base64', **kwargs))
|
|
|
|
@classmethod
|
|
def from_csv(cls, s, columns=None, columns_row=True, **kwargs):
|
|
"""
|
|
Load and decode CSV data from url, filepath or data-string.
|
|
Decoder specific options can be passed using kwargs: https://docs.python.org/3/library/csv.html
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
kwargs['columns'] = columns
|
|
kwargs['columns_row'] = columns_row
|
|
return cls(IODict._decode(s, 'csv', **kwargs))
|
|
|
|
@classmethod
|
|
def from_json(cls, s, **kwargs):
|
|
"""
|
|
Load and decode JSON data from url, filepath or data-string.
|
|
Decoder specific options can be passed using kwargs: https://docs.python.org/3/library/json.html
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
return cls(IODict._decode(s, 'json', **kwargs))
|
|
|
|
@classmethod
|
|
def from_query_string(cls, s, **kwargs):
|
|
"""
|
|
Load and decode query-string from url, filepath or data-string.
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
return cls(IODict._decode(s, 'query_string', **kwargs))
|
|
|
|
@classmethod
|
|
def from_toml(cls, s, **kwargs):
|
|
"""
|
|
Load and decode TOML data from url, filepath or data-string.
|
|
Decoder specific options can be passed using kwargs: https://pypi.org/project/toml/
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
return cls(IODict._decode(s, 'toml', **kwargs))
|
|
|
|
@classmethod
|
|
def from_xml(cls, s, **kwargs):
|
|
"""
|
|
Load and decode XML data from url, filepath or data-string.
|
|
Decoder specific options can be passed using kwargs: https://github.com/martinblech/xmltodict
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
return cls(IODict._decode(s, 'xml', **kwargs))
|
|
|
|
@classmethod
|
|
def from_yaml(cls, s, **kwargs):
|
|
"""
|
|
Load and decode YAML data from url, filepath or data-string.
|
|
Decoder specific options can be passed using kwargs: https://pyyaml.org/wiki/PyYAMLDocumentation
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
"""
|
|
return cls(IODict._decode(s, 'yaml', **kwargs))
|
|
|
|
def to_base64(self, subformat='json', encoding='utf-8', **kwargs):
|
|
"""
|
|
Encode the current dict instance in Base64 format using the given subformat and encoding.
|
|
Encoder specific options can be passed using kwargs.
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
kwargs['subformat'] = subformat
|
|
kwargs['encoding'] = encoding
|
|
return IODict._encode(self, 'base64', **kwargs)
|
|
|
|
def to_csv(self, key='values', columns=None, columns_row=True, **kwargs):
|
|
"""
|
|
Encode the current dict instance in CSV format.
|
|
Encoder specific options can be passed using kwargs: https://docs.python.org/3/library/csv.html
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
kwargs['columns'] = columns
|
|
kwargs['columns_row'] = columns_row
|
|
return IODict._encode(self[key], 'csv', **kwargs)
|
|
|
|
def to_json(self, **kwargs):
|
|
"""
|
|
Encode the current dict instance in JSON format.
|
|
Encoder specific options can be passed using kwargs: https://docs.python.org/3/library/json.html
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
return IODict._encode(self, 'json', **kwargs)
|
|
|
|
def to_query_string(self, **kwargs):
|
|
"""
|
|
Encode the current dict instance in query-string format.
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
return IODict._encode(self, 'query_string', **kwargs)
|
|
|
|
def to_toml(self, **kwargs):
|
|
"""
|
|
Encode the current dict instance in TOML format.
|
|
Encoder specific options can be passed using kwargs: https://pypi.org/project/toml/
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
return IODict._encode(self, 'toml', **kwargs)
|
|
|
|
def to_xml(self, **kwargs):
|
|
"""
|
|
Encode the current dict instance in XML format.
|
|
Encoder specific options can be passed using kwargs: https://github.com/martinblech/xmltodict
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
return IODict._encode(self, 'xml', **kwargs)
|
|
|
|
def to_yaml(self, **kwargs):
|
|
"""
|
|
Encode the current dict instance in YAML format.
|
|
Encoder specific options can be passed using kwargs: https://pyyaml.org/wiki/PyYAMLDocumentation
|
|
Return the encoded string and optionally save it at the specified 'filepath'.
|
|
A ValueError is raised in case of failure.
|
|
"""
|
|
return IODict._encode(self, 'yaml', **kwargs)
|