aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/fsspec/json.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/fsspec/json.py')
-rw-r--r--.venv/lib/python3.12/site-packages/fsspec/json.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/fsspec/json.py b/.venv/lib/python3.12/site-packages/fsspec/json.py
new file mode 100644
index 00000000..69cead04
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fsspec/json.py
@@ -0,0 +1,121 @@
+import json
+from contextlib import suppress
+from pathlib import PurePath
+from typing import (
+ Any,
+ Callable,
+ ClassVar,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Sequence,
+ Tuple,
+)
+
+from .registry import _import_class, get_filesystem_class
+from .spec import AbstractFileSystem
+
+
+class FilesystemJSONEncoder(json.JSONEncoder):
+ include_password: ClassVar[bool] = True
+
+ def default(self, o: Any) -> Any:
+ if isinstance(o, AbstractFileSystem):
+ return o.to_dict(include_password=self.include_password)
+ if isinstance(o, PurePath):
+ cls = type(o)
+ return {"cls": f"{cls.__module__}.{cls.__name__}", "str": str(o)}
+
+ return super().default(o)
+
+ def make_serializable(self, obj: Any) -> Any:
+ """
+ Recursively converts an object so that it can be JSON serialized via
+ :func:`json.dumps` and :func:`json.dump`, without actually calling
+ said functions.
+ """
+ if isinstance(obj, (str, int, float, bool)):
+ return obj
+ if isinstance(obj, Mapping):
+ return {k: self.make_serializable(v) for k, v in obj.items()}
+ if isinstance(obj, Sequence):
+ return [self.make_serializable(v) for v in obj]
+
+ return self.default(obj)
+
+
+class FilesystemJSONDecoder(json.JSONDecoder):
+ def __init__(
+ self,
+ *,
+ object_hook: Optional[Callable[[Dict[str, Any]], Any]] = None,
+ parse_float: Optional[Callable[[str], Any]] = None,
+ parse_int: Optional[Callable[[str], Any]] = None,
+ parse_constant: Optional[Callable[[str], Any]] = None,
+ strict: bool = True,
+ object_pairs_hook: Optional[Callable[[List[Tuple[str, Any]]], Any]] = None,
+ ) -> None:
+ self.original_object_hook = object_hook
+
+ super().__init__(
+ object_hook=self.custom_object_hook,
+ parse_float=parse_float,
+ parse_int=parse_int,
+ parse_constant=parse_constant,
+ strict=strict,
+ object_pairs_hook=object_pairs_hook,
+ )
+
+ @classmethod
+ def try_resolve_path_cls(cls, dct: Dict[str, Any]):
+ with suppress(Exception):
+ fqp = dct["cls"]
+
+ path_cls = _import_class(fqp)
+
+ if issubclass(path_cls, PurePath):
+ return path_cls
+
+ return None
+
+ @classmethod
+ def try_resolve_fs_cls(cls, dct: Dict[str, Any]):
+ with suppress(Exception):
+ if "cls" in dct:
+ try:
+ fs_cls = _import_class(dct["cls"])
+ if issubclass(fs_cls, AbstractFileSystem):
+ return fs_cls
+ except Exception:
+ if "protocol" in dct: # Fallback if cls cannot be imported
+ return get_filesystem_class(dct["protocol"])
+
+ raise
+
+ return None
+
+ def custom_object_hook(self, dct: Dict[str, Any]):
+ if "cls" in dct:
+ if (obj_cls := self.try_resolve_fs_cls(dct)) is not None:
+ return AbstractFileSystem.from_dict(dct)
+ if (obj_cls := self.try_resolve_path_cls(dct)) is not None:
+ return obj_cls(dct["str"])
+
+ if self.original_object_hook is not None:
+ return self.original_object_hook(dct)
+
+ return dct
+
+ def unmake_serializable(self, obj: Any) -> Any:
+ """
+ Inverse function of :meth:`FilesystemJSONEncoder.make_serializable`.
+ """
+ if isinstance(obj, dict):
+ obj = self.custom_object_hook(obj)
+ if isinstance(obj, dict):
+ return {k: self.unmake_serializable(v) for k, v in obj.items()}
+ if isinstance(obj, (list, tuple)):
+ return [self.unmake_serializable(v) for v in obj]
+
+ return obj