]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
json: make JSON readable from dicts and files as well es strings
authorJoerg Behrmann <behrmann@physik.fu-berlin.de>
Wed, 27 Sep 2023 08:38:49 +0000 (10:38 +0200)
committerJoerg Behrmann <behrmann@physik.fu-berlin.de>
Wed, 4 Oct 2023 07:48:04 +0000 (09:48 +0200)
mkosi/config.py
mkosi/types.py

index fbdc2e29e9f34c98647d6d46184f0167783b0c97..9b778570cf1f1548d8d4c3776f01ebabc2c7035a 100644 (file)
@@ -30,7 +30,7 @@ from mkosi.distributions import Distribution, detect_distribution
 from mkosi.log import ARG_DEBUG, ARG_DEBUG_SHELL, Style, die
 from mkosi.pager import page
 from mkosi.run import run
-from mkosi.types import PathString
+from mkosi.types import PathString, SupportsRead
 from mkosi.util import (
     InvokingUser,
     StrEnum,
@@ -673,8 +673,16 @@ class MkosiArgs:
         return json.dumps(dataclasses.asdict(self), cls=MkosiJsonEncoder, indent=indent, sort_keys=sort_keys)
 
     @classmethod
-    def from_json(cls, s: str) -> "MkosiArgs":
-        j = json.loads(s)
+    def from_json(cls, s: Union[str, dict[str, Any], SupportsRead[str], SupportsRead[bytes]]) -> "MkosiArgs":
+        if isinstance(s, str):
+            j = json.loads(s)
+        elif isinstance(s, dict):
+            j = s
+        elif hasattr(s, "read"):
+            j = json.load(s)
+        else:
+            raise ValueError(f"{cls.__name__} can only be constructed from JSON from strings, dictionaries and files.")
+
         transformer = json_type_transformer(cls)
         tj = {k: transformer(k, v) for k, v in j.items()}
         return cls(**tj)
@@ -892,8 +900,16 @@ class MkosiConfig:
         return json.dumps(dataclasses.asdict(self), cls=MkosiJsonEncoder, indent=indent, sort_keys=sort_keys)
 
     @classmethod
-    def from_json(cls, s: str) -> "MkosiConfig":
-        j = json.loads(s)
+    def from_json(cls, s: Union[str, dict[str, Any], SupportsRead[str], SupportsRead[bytes]]) -> "MkosiConfig":
+        if isinstance(s, str):
+            j = json.loads(s)
+        elif isinstance(s, dict):
+            j = s
+        elif hasattr(s, "read"):
+            j = json.load(s)
+        else:
+            raise ValueError(f"{cls.__name__} can only be constructed from JSON from strings, dictionaries and files.")
+
         transformer = json_type_transformer(cls)
         tj = {k: transformer(k, v) for k, v in j.items()}
         return cls(**tj)
index a2a3643b5cbb47c0d68fb56f56cc1a1359b9675b..c6621855c97ce83cbbebc8db4f62d21415f04c1e 100644 (file)
@@ -2,7 +2,7 @@
 
 import subprocess
 from pathlib import Path
-from typing import IO, TYPE_CHECKING, Any, Union
+from typing import IO, TYPE_CHECKING, Any, Protocol, TypeVar, Union
 
 # These types are only generic during type checking and not at runtime, leading
 # to a TypeError during compilation.
@@ -17,3 +17,12 @@ else:
 # Borrowed from https://github.com/python/typeshed/blob/3d14016085aed8bcf0cf67e9e5a70790ce1ad8ea/stdlib/3/subprocess.pyi#L24
 _FILE = Union[None, int, IO[Any]]
 PathString = Union[Path, str]
+
+# Borrowed from
+# https://github.com/python/typeshed/blob/ec52bf1adde1d3183d0595d2ba982589df48dff1/stdlib/_typeshed/__init__.pyi#L19
+# and
+# https://github.com/python/typeshed/blob/ec52bf1adde1d3183d0595d2ba982589df48dff1/stdlib/_typeshed/__init__.pyi#L224
+_T_co = TypeVar("_T_co", covariant=True)
+
+class SupportsRead(Protocol[_T_co]):
+    def read(self, __length: int = ...) -> _T_co: ...