python-benedict/benedict/dicts/io.py

191 lines
7.7 KiB
Python
Raw Normal View History

2019-09-10 14:58:26 +00:00
# -*- coding: utf-8 -*-
from benedict.utils import io_util, type_util
2019-09-10 14:58:26 +00:00
class IODict(dict):
def __init__(self, *args, **kwargs):
2019-12-12 17:24:16 +00:00
"""
Constructs a new instance.
"""
2020-01-25 11:08:24 +00:00
# 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]):
2020-01-25 11:08:24 +00:00
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):
2020-01-25 11:08:24 +00:00
return d
raise ValueError('Invalid string data input.')
2019-09-10 14:58:26 +00:00
@staticmethod
def _decode(s, format, **kwargs):
2019-09-10 14:58:26 +00:00
d = None
try:
2019-10-03 16:42:44 +00:00
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):
2019-09-17 09:50:06 +00:00
d = data
elif type_util.is_list(data):
2019-09-17 09:50:06 +00:00
# force list to dict
d = { 'values': data }
2019-09-17 09:50:06 +00:00
else:
raise ValueError(
'Invalid data type: {}, expected dict or list.'.format(type(data)))
2019-09-10 14:58:26 +00:00
except Exception as e:
raise ValueError(
'Invalid data or url or filepath input argument: {}\n{}'.format(s, e))
2019-09-10 14:58:26 +00:00
return d
@staticmethod
def _encode(d, format, **kwargs):
filepath = kwargs.pop('filepath', None)
s = io_util.encode(d, format, **kwargs)
2019-09-10 14:58:26 +00:00
if filepath:
io_util.write_file(filepath, s)
return s
@classmethod
def from_base64(cls, s, subformat='json', encoding='utf-8', **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-09-10 14:58:26 +00:00
@classmethod
def from_csv(cls, s, columns=None, columns_row=True, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-10-03 16:45:22 +00:00
@classmethod
def from_json(cls, s, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-09-10 14:58:26 +00:00
@classmethod
def from_query_string(cls, s, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-10-14 12:47:11 +00:00
@classmethod
def from_toml(cls, s, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-09-20 14:21:04 +00:00
@classmethod
def from_xml(cls, s, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-09-23 12:13:52 +00:00
@classmethod
def from_yaml(cls, s, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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))
2019-09-17 09:50:06 +00:00
def to_base64(self, subformat='json', encoding='utf-8', **kwargs):
2019-12-12 17:24:16 +00:00
"""
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
2019-10-29 15:22:24 +00:00
kwargs['encoding'] = encoding
return IODict._encode(self, 'base64', **kwargs)
def to_csv(self, key='values', columns=None, columns_row=True, **kwargs):
2019-12-12 17:24:16 +00:00
"""
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):
2019-12-12 17:24:16 +00:00
"""
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):
2019-12-12 17:24:16 +00:00
"""
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):
2019-12-12 17:24:16 +00:00
"""
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):
2019-12-12 17:24:16 +00:00
"""
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):
2019-12-12 17:24:16 +00:00
"""
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)