File: from_file.py

package info (click to toggle)
python-box 7.3.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 572 kB
  • sloc: python: 3,471; makefile: 4
file content (149 lines) | stat: -rw-r--r-- 5,017 bytes parent folder | download
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}")