1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from json import JSONDecodeError
from os import PathLike
from pathlib import Path
from typing import Optional, Callable, Dict, Union
import sys
from box.box import Box
from box.box_list import BoxList
from box.converters import msgpack_available, toml_read_library, yaml_available, toml_decode_error
from box.exceptions import BoxError
try:
from ruamel.yaml import YAMLError
except ImportError:
try:
from yaml import YAMLError # type: ignore
except ImportError:
YAMLError = False # type: ignore
try:
from msgpack import UnpackException # type: ignore
except ImportError:
UnpackException = False # type: ignore
__all__ = ["box_from_file", "box_from_string"]
def _to_json(file, encoding, errors, **kwargs):
try:
return Box.from_json(filename=file, encoding=encoding, errors=errors, **kwargs)
except JSONDecodeError:
raise BoxError("File is not JSON as expected")
except BoxError:
return BoxList.from_json(filename=file, encoding=encoding, errors=errors, **kwargs)
def _to_csv(file, encoding, errors, **kwargs):
return BoxList.from_csv(filename=file, encoding=encoding, errors=errors, **kwargs)
def _to_yaml(file, encoding, errors, **kwargs):
if not yaml_available:
raise BoxError(
f'File "{file}" is yaml but no package is available to open it. Please install "ruamel.yaml" or "PyYAML"'
)
try:
return Box.from_yaml(filename=file, encoding=encoding, errors=errors, **kwargs)
except YAMLError:
raise BoxError("File is not YAML as expected")
except BoxError:
return BoxList.from_yaml(filename=file, encoding=encoding, errors=errors, **kwargs)
def _to_toml(file, encoding, errors, **kwargs):
if not toml_read_library:
raise BoxError(f'File "{file}" is toml but no package is available to open it. Please install "tomli"')
try:
return Box.from_toml(filename=file, encoding=encoding, errors=errors, **kwargs)
except toml_decode_error:
raise BoxError("File is not TOML as expected")
def _to_msgpack(file, _, __, **kwargs):
if not msgpack_available:
raise BoxError(f'File "{file}" is msgpack but no package is available to open it. Please install "msgpack"')
try:
return Box.from_msgpack(filename=file, **kwargs)
except (UnpackException, ValueError):
raise BoxError("File is not msgpack as expected")
except BoxError:
return BoxList.from_msgpack(filename=file, **kwargs)
converters = {
"json": _to_json,
"jsn": _to_json,
"yaml": _to_yaml,
"yml": _to_yaml,
"toml": _to_toml,
"tml": _to_toml,
"msgpack": _to_msgpack,
"pack": _to_msgpack,
"csv": _to_csv,
} # type: Dict[str, Callable]
def box_from_file(
file: Union[str, PathLike],
file_type: Optional[str] = None,
encoding: str = "utf-8",
errors: str = "strict",
**kwargs,
) -> Union[Box, BoxList]:
"""
Loads the provided file and tries to parse it into a Box or BoxList object as appropriate.
:param file: Location of file
:param encoding: File encoding
:param errors: How to handle encoding errors
:param file_type: manually specify file type: json, toml or yaml
:return: Box or BoxList
"""
if not isinstance(file, Path):
file = Path(file)
if not file.exists():
raise BoxError(f'file "{file}" does not exist')
file_type = file_type or file.suffix
file_type = file_type.lower().lstrip(".")
if file_type.lower() in converters:
return converters[file_type.lower()](file, encoding, errors, **kwargs) # type: ignore
raise BoxError(f'"{file_type}" is an unknown type. Please use either csv, toml, msgpack, yaml or json')
def box_from_string(content: str, string_type: str = "json") -> Union[Box, BoxList]:
"""
Parse the provided string into a Box or BoxList object as appropriate.
:param content: String to parse
:param string_type: manually specify file type: json, toml or yaml
:return: Box or BoxList
"""
if string_type == "json":
try:
return Box.from_json(json_string=content)
except JSONDecodeError:
raise BoxError("File is not JSON as expected")
except BoxError:
return BoxList.from_json(json_string=content)
elif string_type == "toml":
try:
return Box.from_toml(toml_string=content)
except toml_decode_error: # type: ignore
raise BoxError("File is not TOML as expected")
except BoxError:
return BoxList.from_toml(toml_string=content)
elif string_type == "yaml":
try:
return Box.from_yaml(yaml_string=content)
except YAMLError:
raise BoxError("File is not YAML as expected")
except BoxError:
return BoxList.from_yaml(yaml_string=content)
else:
raise BoxError(f"Unsupported string_string of {string_type}")
|