2019-09-10 14:58:26 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2020-09-17 17:05:55 +00:00
|
|
|
from benedict.dicts.base import BaseDict
|
2020-02-03 17:25:54 +00:00
|
|
|
from benedict.dicts.io import io_util
|
|
|
|
from benedict.utils import type_util
|
2019-09-10 14:58:26 +00:00
|
|
|
|
|
|
|
|
2020-09-17 17:05:55 +00:00
|
|
|
class IODict(BaseDict):
|
2019-09-10 14:58:26 +00:00
|
|
|
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.
|
2019-11-07 16:45:45 +00:00
|
|
|
# use 'format' kwarg to specify the decoder to use, default 'json'.
|
2020-09-09 14:47:25 +00:00
|
|
|
if len(args) == 1 and type_util.is_string(args[0]):
|
2020-03-13 12:54:53 +00:00
|
|
|
d = IODict._decode_init(args[0], **kwargs)
|
2020-01-25 11:08:24 +00:00
|
|
|
super(IODict, self).__init__(d)
|
|
|
|
return
|
|
|
|
super(IODict, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
@staticmethod
|
2020-03-13 12:54:53 +00:00
|
|
|
def _decode_init(s, **kwargs):
|
2020-08-12 10:46:52 +00:00
|
|
|
autodetected_format = io_util.autodetect_format(s)
|
2022-02-13 10:35:43 +00:00
|
|
|
default_format = autodetected_format or "json"
|
|
|
|
format = kwargs.pop("format", default_format).lower()
|
2020-01-25 11:08:24 +00:00
|
|
|
# decode data-string and initialize with dict data.
|
2020-08-12 10:47:43 +00:00
|
|
|
return IODict._decode(s, format, **kwargs)
|
2019-09-10 14:58:26 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2019-11-07 16:45:45 +00:00
|
|
|
def _decode(s, format, **kwargs):
|
2022-10-05 14:43:46 +00:00
|
|
|
data = None
|
2019-09-10 14:58:26 +00:00
|
|
|
try:
|
2022-10-05 14:43:46 +00:00
|
|
|
data = io_util.decode(s, format, **kwargs)
|
2019-09-10 14:58:26 +00:00
|
|
|
except Exception as e:
|
2022-02-18 00:02:02 +00:00
|
|
|
raise ValueError(f"Invalid data or url or filepath argument: {s}\n{e}")
|
2022-10-05 14:43:46 +00:00
|
|
|
# if possible return data as dict, otherwise raise exception
|
|
|
|
if type_util.is_dict(data):
|
|
|
|
return data
|
|
|
|
elif type_util.is_list(data):
|
|
|
|
# force list to dict
|
|
|
|
return {"values": data}
|
|
|
|
else:
|
|
|
|
raise ValueError(f"Invalid data type: {type(data)}, expected dict or list.")
|
2019-09-10 14:58:26 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2019-11-07 16:45:45 +00:00
|
|
|
def _encode(d, format, **kwargs):
|
|
|
|
s = io_util.encode(d, format, **kwargs)
|
2019-09-10 14:58:26 +00:00
|
|
|
return s
|
|
|
|
|
2019-11-11 13:37:24 +00:00
|
|
|
@classmethod
|
2022-02-13 10:35:43 +00:00
|
|
|
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.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
kwargs["subformat"] = subformat
|
|
|
|
kwargs["encoding"] = encoding
|
|
|
|
return cls(s, format="base64", **kwargs)
|
2019-09-10 14:58:26 +00:00
|
|
|
|
2019-11-11 13:37:24 +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.
|
2020-02-04 10:29:00 +00:00
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
https://docs.python.org/3/library/csv.html
|
2019-12-12 17:24:16 +00:00
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
kwargs["columns"] = columns
|
|
|
|
kwargs["columns_row"] = columns_row
|
|
|
|
return cls(s, format="csv", **kwargs)
|
2019-10-03 16:45:22 +00:00
|
|
|
|
2021-05-04 21:22:11 +00:00
|
|
|
@classmethod
|
|
|
|
def from_ini(cls, s, **kwargs):
|
|
|
|
"""
|
|
|
|
Load and decode INI data from url, filepath or data-string.
|
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
https://docs.python.org/3/library/configparser.html
|
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="ini", **kwargs)
|
2021-05-04 21:22:11 +00:00
|
|
|
|
2020-02-21 12:54:08 +00:00
|
|
|
@classmethod
|
2020-09-09 10:22:56 +00:00
|
|
|
def from_json(cls, s, **kwargs):
|
2020-02-21 12:54:08 +00:00
|
|
|
"""
|
2020-09-09 10:22:56 +00:00
|
|
|
Load and decode JSON data from url, filepath or data-string.
|
2020-02-21 12:54:08 +00:00
|
|
|
Decoder specific options can be passed using kwargs:
|
2020-09-09 10:22:56 +00:00
|
|
|
https://docs.python.org/3/library/json.html
|
2020-02-21 12:54:08 +00:00
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="json", **kwargs)
|
2020-02-21 12:54:08 +00:00
|
|
|
|
2019-11-11 13:37:24 +00:00
|
|
|
@classmethod
|
2020-09-09 10:22:56 +00:00
|
|
|
def from_pickle(cls, s, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
2020-09-09 10:22:56 +00:00
|
|
|
Load and decode a pickle encoded in Base64 format data from url, filepath or data-string.
|
2020-02-04 10:29:00 +00:00
|
|
|
Decoder specific options can be passed using kwargs:
|
2020-09-09 10:22:56 +00:00
|
|
|
https://docs.python.org/3/library/pickle.html
|
2019-12-12 17:24:16 +00:00
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="pickle", **kwargs)
|
2019-09-10 14:58:26 +00:00
|
|
|
|
2020-09-09 14:45:39 +00:00
|
|
|
@classmethod
|
|
|
|
def from_plist(cls, s, **kwargs):
|
|
|
|
"""
|
|
|
|
Load and decode p-list data from url, filepath or data-string.
|
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
https://docs.python.org/3/library/plistlib.html
|
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="plist", **kwargs)
|
2020-09-09 14:45:39 +00:00
|
|
|
|
2019-11-11 13:37:24 +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.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="query_string", **kwargs)
|
2019-10-14 12:47:11 +00:00
|
|
|
|
2019-11-11 13:37:24 +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.
|
2020-02-04 10:29:00 +00:00
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
https://pypi.org/project/toml/
|
2019-12-12 17:24:16 +00:00
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="toml", **kwargs)
|
2019-09-20 14:21:04 +00:00
|
|
|
|
2022-10-05 14:43:46 +00:00
|
|
|
@classmethod
|
|
|
|
def from_xls(cls, s, sheet=0, columns=None, columns_row=True, **kwargs):
|
|
|
|
"""
|
|
|
|
Load and decode XLS files (".xls", ".xlsx", ".xlsm") from url, filepath or data-string.
|
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
- https://openpyxl.readthedocs.io/ (for .xlsx and .xlsm files)
|
|
|
|
- https://pypi.org/project/xlrd/ (for .xls files)
|
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
|
|
|
kwargs["sheet"] = sheet
|
|
|
|
kwargs["columns"] = columns
|
|
|
|
kwargs["columns_row"] = columns_row
|
|
|
|
return cls(s, format="xls", **kwargs)
|
|
|
|
|
2019-11-11 13:37:24 +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.
|
2020-02-04 10:29:00 +00:00
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
https://github.com/martinblech/xmltodict
|
2019-12-12 17:24:16 +00:00
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="xml", **kwargs)
|
2019-09-23 12:13:52 +00:00
|
|
|
|
2019-11-11 13:37:24 +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.
|
2020-02-04 10:29:00 +00:00
|
|
|
Decoder specific options can be passed using kwargs:
|
|
|
|
https://pyyaml.org/wiki/PyYAMLDocumentation
|
2019-12-12 17:24:16 +00:00
|
|
|
Return a new dict instance. A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return cls(s, format="yaml", **kwargs)
|
2019-09-17 09:50:06 +00:00
|
|
|
|
2022-02-13 10:35:43 +00:00
|
|
|
def to_base64(self, subformat="json", encoding="utf-8", **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
2020-02-04 10:29:00 +00:00
|
|
|
Encode the current dict instance in Base64 format
|
|
|
|
using the given subformat and encoding.
|
2019-12-12 17:24:16 +00:00
|
|
|
Encoder specific options can be passed using kwargs.
|
2020-02-04 10:29:00 +00:00
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
kwargs["subformat"] = subformat
|
|
|
|
kwargs["encoding"] = encoding
|
|
|
|
return self._encode(self.dict(), "base64", **kwargs)
|
2019-11-07 16:45:45 +00:00
|
|
|
|
2022-02-13 10:35:43 +00:00
|
|
|
def to_csv(self, key="values", columns=None, columns_row=True, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
2021-04-23 10:56:00 +00:00
|
|
|
Encode a list of dicts in the current dict instance in CSV format.
|
2020-02-04 10:29:00 +00:00
|
|
|
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 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
kwargs["columns"] = columns
|
|
|
|
kwargs["columns_row"] = columns_row
|
|
|
|
return self._encode(self.dict()[key], "csv", **kwargs)
|
2019-11-07 16:45:45 +00:00
|
|
|
|
2021-05-04 21:22:11 +00:00
|
|
|
def to_ini(self, **kwargs):
|
|
|
|
"""
|
|
|
|
Encode the current dict instance in INI format.
|
|
|
|
Encoder specific options can be passed using kwargs:
|
|
|
|
https://docs.python.org/3/library/configparser.html
|
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "ini", **kwargs)
|
2021-05-04 21:22:11 +00:00
|
|
|
|
2020-09-09 10:22:56 +00:00
|
|
|
def to_json(self, **kwargs):
|
2020-02-21 12:54:08 +00:00
|
|
|
"""
|
2020-09-09 10:22:56 +00:00
|
|
|
Encode the current dict instance in JSON format.
|
2020-02-21 12:54:08 +00:00
|
|
|
Encoder specific options can be passed using kwargs:
|
2020-09-09 10:22:56 +00:00
|
|
|
https://docs.python.org/3/library/json.html
|
2020-02-21 12:54:08 +00:00
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "json", **kwargs)
|
2020-02-21 12:54:08 +00:00
|
|
|
|
2020-09-09 10:22:56 +00:00
|
|
|
def to_pickle(self, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
2020-09-09 10:22:56 +00:00
|
|
|
Encode the current dict instance as pickle (encoded in Base64).
|
|
|
|
The pickle protocol used by default is 2.
|
2020-02-04 10:29:00 +00:00
|
|
|
Encoder specific options can be passed using kwargs:
|
2020-09-09 10:22:56 +00:00
|
|
|
https://docs.python.org/3/library/pickle.html
|
2020-02-04 10:29:00 +00:00
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "pickle", **kwargs)
|
2019-11-07 16:45:45 +00:00
|
|
|
|
2020-09-09 14:45:39 +00:00
|
|
|
def to_plist(self, **kwargs):
|
|
|
|
"""
|
|
|
|
Encode the current dict instance as p-list.
|
|
|
|
Encoder specific options can be passed using kwargs:
|
|
|
|
https://docs.python.org/3/library/plistlib.html
|
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "plist", **kwargs)
|
2020-09-09 14:45:39 +00:00
|
|
|
|
2019-11-07 16:45:45 +00:00
|
|
|
def to_query_string(self, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
|
|
|
Encode the current dict instance in query-string format.
|
2020-02-04 10:29:00 +00:00
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "query_string", **kwargs)
|
2019-11-07 16:45:45 +00:00
|
|
|
|
|
|
|
def to_toml(self, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
|
|
|
Encode the current dict instance in TOML format.
|
2020-02-04 10:29:00 +00:00
|
|
|
Encoder specific options can be passed using kwargs:
|
|
|
|
https://pypi.org/project/toml/
|
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "toml", **kwargs)
|
2019-11-07 16:45:45 +00:00
|
|
|
|
|
|
|
def to_xml(self, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
|
|
|
Encode the current dict instance in XML format.
|
2020-02-04 10:29:00 +00:00
|
|
|
Encoder specific options can be passed using kwargs:
|
|
|
|
https://github.com/martinblech/xmltodict
|
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "xml", **kwargs)
|
2019-11-07 16:45:45 +00:00
|
|
|
|
2022-10-05 14:43:46 +00:00
|
|
|
def to_xls(
|
|
|
|
self,
|
|
|
|
key="values",
|
|
|
|
sheet=0,
|
|
|
|
columns=None,
|
|
|
|
columns_row=True,
|
|
|
|
format="xlsx",
|
|
|
|
**kwargs,
|
|
|
|
):
|
|
|
|
"""
|
|
|
|
Encode a list of dicts in the current dict instance in XLS format.
|
|
|
|
Encoder specific options can be passed using kwargs:
|
|
|
|
- https://openpyxl.readthedocs.io/ (for .xlsx and .xlsm files)
|
|
|
|
- https://pypi.org/project/xlrd/ (for .xls files)
|
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
|
|
|
# kwargs["sheet"] = sheet
|
|
|
|
# kwargs["columns"] = columns
|
|
|
|
# kwargs["columns_row"] = columns_row
|
|
|
|
# kwargs["format"] = format
|
|
|
|
# return self._encode(self.dict()[key], "xls", **kwargs)
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2019-11-07 16:45:45 +00:00
|
|
|
def to_yaml(self, **kwargs):
|
2019-12-12 17:24:16 +00:00
|
|
|
"""
|
|
|
|
Encode the current dict instance in YAML format.
|
2020-02-04 10:29:00 +00:00
|
|
|
Encoder specific options can be passed using kwargs:
|
|
|
|
https://pyyaml.org/wiki/PyYAMLDocumentation
|
|
|
|
Return the encoded string and optionally save it at 'filepath'.
|
2019-12-12 17:24:16 +00:00
|
|
|
A ValueError is raised in case of failure.
|
|
|
|
"""
|
2022-02-13 10:35:43 +00:00
|
|
|
return self._encode(self.dict(), "yaml", **kwargs)
|