turbo_broccoli.custom.external

External data. Embeds data from another file (decodable using turbo_broccoli.native.load) into a JSON document. The data is wrapped in a ExternalData objects. Note that the path of a ExternalData is relative to the path of the JSON file containing it. Therefore, it is not possible to serialize/deserialize a ExternalData object without a context that points to an actual JSON file.

Warning: The data is read-only. Modifying ExternalData.data will not affect the data file.

 1"""
 2External data. Embeds data from another file (decodable using
 3`turbo_broccoli.native.load`) into a JSON document. The data is wrapped in a
 4`ExternalData` objects. Note that the path of a `ExternalData` is relative to
 5the path of the JSON file containing it. Therefore, it is not possible to
 6serialize/deserialize a `ExternalData` object without a context that points to
 7an actual JSON file.
 8
 9Warning:
10    The data is read-only. Modifying `ExternalData.data` will not affect the
11    data file.
12"""
13
14# pylint: disable=cyclic-import
15# pylint: disable=import-outside-toplevel  # to avoid actual circular imports
16
17
18from pathlib import Path
19from typing import Any
20
21from turbo_broccoli.context import Context
22from turbo_broccoli.exceptions import DeserializationError, TypeNotSupported
23
24
25class ExternalData:
26    """Encapsulate the data of a file"""
27
28    path: Path
29    data: Any
30
31    def __init__(self, path: Path | str, ctx: Context) -> None:
32        """
33        Args:
34            path (Path | str): Path of the data file. Either absolute or
35                relative to `ctx.file_path`
36            ctx (Context):
37        """
38        from turbo_broccoli.native import load as native_load
39
40        if ctx.file_path is None:
41            raise ValueError("Context must have a file path")
42        path = Path(path) if isinstance(path, str) else path
43        if path.is_absolute():
44            self.path = Path(path).relative_to(ctx.file_path.parent.absolute())
45        else:
46            self.path = path
47        self.data = native_load(ctx.file_path.parent / self.path)
48
49
50def _json_to_externaldata(dct: dict, ctx: Context) -> ExternalData:
51    decoders = {
52        1: _json_to_externaldata_v1,
53        2: _json_to_externaldata_v2,
54    }
55    return decoders[dct["__version__"]](dct, ctx)
56
57
58def _json_to_externaldata_v1(dct: dict, ctx: Context) -> ExternalData:
59    return ExternalData(dct["path"], ctx)
60
61
62def _json_to_externaldata_v2(dct: dict, ctx: Context) -> ExternalData:
63    ctx.raise_if_nodecode("pathlib.path")
64    return ExternalData(dct["path"], ctx)
65
66
67# pylint: disable=missing-function-docstring
68def from_json(dct: dict, ctx: Context) -> ExternalData:
69    decoders = {
70        "external": _json_to_externaldata,
71    }
72    try:
73        type_name = dct["__type__"]
74        return decoders[type_name](dct, ctx)
75    except KeyError as exc:
76        raise DeserializationError() from exc
77
78
79def to_json(obj: Any, ctx: Context) -> dict:
80    """
81    Serializes an `ExternalData` object into JSON. The return dict has the
82    following structure
83
84    ```py
85    {
86        "__type__": "external",
87        "__version__": 2,
88        "path": {...}
89    }
90    ```
91
92    where `path` is a (serialized) `pathlib.Path` object, and relative to the
93    path of the input/output JSON file.
94    """
95    if not isinstance(obj, ExternalData):
96        raise TypeNotSupported()
97    return {"__type__": "external", "__version__": 2, "path": obj.path}
class ExternalData:
26class ExternalData:
27    """Encapsulate the data of a file"""
28
29    path: Path
30    data: Any
31
32    def __init__(self, path: Path | str, ctx: Context) -> None:
33        """
34        Args:
35            path (Path | str): Path of the data file. Either absolute or
36                relative to `ctx.file_path`
37            ctx (Context):
38        """
39        from turbo_broccoli.native import load as native_load
40
41        if ctx.file_path is None:
42            raise ValueError("Context must have a file path")
43        path = Path(path) if isinstance(path, str) else path
44        if path.is_absolute():
45            self.path = Path(path).relative_to(ctx.file_path.parent.absolute())
46        else:
47            self.path = path
48        self.data = native_load(ctx.file_path.parent / self.path)

Encapsulate the data of a file

ExternalData(path: pathlib.Path | str, ctx: turbo_broccoli.context.Context)
32    def __init__(self, path: Path | str, ctx: Context) -> None:
33        """
34        Args:
35            path (Path | str): Path of the data file. Either absolute or
36                relative to `ctx.file_path`
37            ctx (Context):
38        """
39        from turbo_broccoli.native import load as native_load
40
41        if ctx.file_path is None:
42            raise ValueError("Context must have a file path")
43        path = Path(path) if isinstance(path, str) else path
44        if path.is_absolute():
45            self.path = Path(path).relative_to(ctx.file_path.parent.absolute())
46        else:
47            self.path = path
48        self.data = native_load(ctx.file_path.parent / self.path)

Args: path (Path | str): Path of the data file. Either absolute or relative to ctx.file_path ctx (Context):

path: pathlib.Path
data: Any
def from_json( dct: dict, ctx: turbo_broccoli.context.Context) -> ExternalData:
69def from_json(dct: dict, ctx: Context) -> ExternalData:
70    decoders = {
71        "external": _json_to_externaldata,
72    }
73    try:
74        type_name = dct["__type__"]
75        return decoders[type_name](dct, ctx)
76    except KeyError as exc:
77        raise DeserializationError() from exc
def to_json(obj: Any, ctx: turbo_broccoli.context.Context) -> dict:
80def to_json(obj: Any, ctx: Context) -> dict:
81    """
82    Serializes an `ExternalData` object into JSON. The return dict has the
83    following structure
84
85    ```py
86    {
87        "__type__": "external",
88        "__version__": 2,
89        "path": {...}
90    }
91    ```
92
93    where `path` is a (serialized) `pathlib.Path` object, and relative to the
94    path of the input/output JSON file.
95    """
96    if not isinstance(obj, ExternalData):
97        raise TypeNotSupported()
98    return {"__type__": "external", "__version__": 2, "path": obj.path}

Serializes an ExternalData object into JSON. The return dict has the following structure

{
    "__type__": "external",
    "__version__": 2,
    "path": {...}
}

where path is a (serialized) pathlib.Path object, and relative to the path of the input/output JSON file.