]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager: datamodel: extract custom file types to a separate module
authorVasek Sraier <git@vakabus.cz>
Wed, 8 Mar 2023 14:51:35 +0000 (15:51 +0100)
committerVasek Sraier <git@vakabus.cz>
Tue, 28 Mar 2023 13:24:22 +0000 (15:24 +0200)
manager/knot_resolver_manager/datamodel/types/__init__.py
manager/knot_resolver_manager/datamodel/types/files.py [new file with mode: 0644]
manager/knot_resolver_manager/datamodel/types/types.py
manager/tests/unit/datamodel/types/test_custom_types.py

index 225a8f444d1bdac152380eda15abc98e1066ff0c..bdd22c824b05a8f65f546433147018f6a75c770b 100644 (file)
@@ -1,10 +1,7 @@
 from .enums import DNSRecordTypeEnum, PolicyActionEnum, PolicyFlagEnum
+from .files import AbsoluteDir, Dir, File, FilePath
 from .types import (
-    AbsoluteDir,
-    Dir,
     DomainName,
-    File,
-    FilePath,
     Int0_512,
     Int0_65535,
     InterfaceName,
diff --git a/manager/knot_resolver_manager/datamodel/types/files.py b/manager/knot_resolver_manager/datamodel/types/files.py
new file mode 100644 (file)
index 0000000..73db8b7
--- /dev/null
@@ -0,0 +1,145 @@
+from pathlib import Path
+from typing import Any, Dict, Tuple, Type, TypeVar
+
+from knot_resolver_manager.utils.modeling.base_value_type import BaseValueType
+
+
+class UncheckedPath(BaseValueType):
+    """
+    Wrapper around pathlib.Path object. Can represent pretty much any Path. No checks are
+    performed on the value. The value is taken as is.
+    """
+
+    _value: Path
+
+    def __init__(
+        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
+    ) -> None:
+
+        super().__init__(source_value, object_path=object_path)
+        self._object_path: str = object_path
+        self._parents: Tuple[UncheckedPath, ...] = parents
+        if isinstance(source_value, str):
+            self._raw_value: str = source_value
+            if self._parents:
+                pp = map(lambda p: p.to_path(), self._parents)
+                self._value: Path = Path(*pp, source_value)
+            else:
+                self._value: Path = Path(source_value)
+        else:
+            raise ValueError(f"expected file path in a string, got '{source_value}' with type '{type(source_value)}'.")
+
+    def __str__(self) -> str:
+        return str(self._value)
+
+    def __eq__(self, o: object) -> bool:
+        if not isinstance(o, UncheckedPath):
+            return False
+
+        return o._value == self._value
+
+    def __int__(self) -> int:
+        raise RuntimeError("Path cannot be converted to type <int>")
+
+    def to_path(self) -> Path:
+        return self._value
+
+    def serialize(self) -> Any:
+        return self._raw_value
+
+    def relative_to(self, parent: "UncheckedPath") -> "UncheckedPath":
+        """return a path with an added parent part"""
+        return UncheckedPath(self._raw_value, parents=(parent, *self._parents), object_path=self._object_path)
+
+    UPT = TypeVar("UPT", bound="UncheckedPath")
+
+    def reconstruct(self, cls: Type[UPT]) -> UPT:
+        """
+        Rebuild this object as an instance of its subclass. Practically, allows for conversions from
+        """
+        return cls(self._raw_value, parents=self._parents, object_path=self._object_path)
+
+    @classmethod
+    def json_schema(cls: Type["UncheckedPath"]) -> Dict[Any, Any]:
+        return {
+            "type": "string",
+        }
+
+
+class Dir(UncheckedPath):
+    """
+    Path, that is enforced to be:
+    - an existing directory
+    """
+
+    def __init__(
+        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
+    ) -> None:
+        super().__init__(source_value, parents=parents, object_path=object_path)
+        if not self._value.is_dir():
+            raise ValueError("path does not point to an existing directory")
+
+
+class AbsoluteDir(Dir):
+    """
+    Path, that is enforced to be:
+    - absolute
+    - an existing directory
+    """
+
+    def __init__(
+        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
+    ) -> None:
+        super().__init__(source_value, parents=parents, object_path=object_path)
+        if not self._value.is_absolute():
+            raise ValueError("path not absolute")
+
+
+class File(UncheckedPath):
+    """
+    Path, that is enforced to be:
+    - an existing file
+    """
+
+    def __init__(
+        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
+    ) -> None:
+        super().__init__(source_value, parents=parents, object_path=object_path)
+        if not self._value.exists():
+            raise ValueError("file does not exist")
+        if not self._value.is_file():
+            raise ValueError("path is not a file")
+
+
+class FilePath(UncheckedPath):
+    """
+    Path, that is enforced to be:
+    - parent of the last path segment is an existing directory
+    - it does not point to a dir
+    """
+
+    def __init__(
+        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
+    ) -> None:
+        super().__init__(source_value, parents=parents, object_path=object_path)
+        p = self._value.parent
+        if not p.exists() or not p.is_dir():
+            raise ValueError("path does not point inside an existing directory")
+        if self._value.is_dir():
+            raise ValueError("path points to a directory when we expected a file")
+
+
+class CheckedPath(UncheckedPath):
+    """
+    Like UncheckedPath, but the file path is checked for being valid. So no non-existent directories in the middle,
+    no symlink loops. This however means, that resolving of relative path happens while validating.
+    """
+
+    def __init__(
+        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
+    ) -> None:
+        super().__init__(source_value, parents=parents, object_path=object_path)
+        try:
+            self._value = self._value.resolve(strict=False)
+        except RuntimeError as e:
+            raise ValueError("Failed to resolve given file path. Is there a symlink loop?") from e
index d9f725acd7fb0ffc7f152b7eefb6b9e41b760764..fceb51e8968f6cd9c797452680e7c7d59203de84 100644 (file)
@@ -399,144 +399,3 @@ class IPv6Network96(BaseValueType):
     @classmethod
     def json_schema(cls: Type["IPv6Network96"]) -> Dict[Any, Any]:
         return {"type": "string"}
-
-
-class UncheckedPath(BaseValueType):
-    """
-    Wrapper around pathlib.Path object. Can represent pretty much any Path. No checks are
-    performed on the value. The value is taken as is.
-    """
-
-    _value: Path
-
-    def __init__(
-        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
-    ) -> None:
-
-        super().__init__(source_value, object_path=object_path)
-        self._object_path: str = object_path
-        self._parents: Tuple[UncheckedPath, ...] = parents
-        if isinstance(source_value, str):
-            self._raw_value: str = source_value
-            if self._parents:
-                pp = map(lambda p: p.to_path(), self._parents)
-                self._value: Path = Path(*pp, source_value)
-            else:
-                self._value: Path = Path(source_value)
-        else:
-            raise ValueError(f"expected file path in a string, got '{source_value}' with type '{type(source_value)}'.")
-
-    def __str__(self) -> str:
-        return str(self._value)
-
-    def __eq__(self, o: object) -> bool:
-        if not isinstance(o, UncheckedPath):
-            return False
-
-        return o._value == self._value
-
-    def __int__(self) -> int:
-        raise RuntimeError("Path cannot be converted to type <int>")
-
-    def to_path(self) -> Path:
-        return self._value
-
-    def serialize(self) -> Any:
-        return self._raw_value
-
-    def relative_to(self, parent: "UncheckedPath") -> "UncheckedPath":
-        """return a path with an added parent part"""
-        return UncheckedPath(self._raw_value, parents=(parent, *self._parents), object_path=self._object_path)
-
-    UPT = TypeVar("UPT", bound="UncheckedPath")
-
-    def reconstruct(self, cls: Type[UPT]) -> UPT:
-        """
-        Rebuild this object as an instance of its subclass. Practically, allows for conversions from
-        """
-        return cls(self._raw_value, parents=self._parents, object_path=self._object_path)
-
-    @classmethod
-    def json_schema(cls: Type["UncheckedPath"]) -> Dict[Any, Any]:
-        return {
-            "type": "string",
-        }
-
-
-class Dir(UncheckedPath):
-    """
-    Path, that is enforced to be:
-    - an existing directory
-    """
-
-    def __init__(
-        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
-    ) -> None:
-        super().__init__(source_value, parents=parents, object_path=object_path)
-        if not self._value.is_dir():
-            raise ValueError("path does not point to an existing directory")
-
-
-class AbsoluteDir(Dir):
-    """
-    Path, that is enforced to be:
-    - absolute
-    - an existing directory
-    """
-
-    def __init__(
-        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
-    ) -> None:
-        super().__init__(source_value, parents=parents, object_path=object_path)
-        if not self._value.is_absolute():
-            raise ValueError("path not absolute")
-
-
-class File(UncheckedPath):
-    """
-    Path, that is enforced to be:
-    - an existing file
-    """
-
-    def __init__(
-        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
-    ) -> None:
-        super().__init__(source_value, parents=parents, object_path=object_path)
-        if not self._value.exists():
-            raise ValueError("file does not exist")
-        if not self._value.is_file():
-            raise ValueError("path is not a file")
-
-
-class FilePath(UncheckedPath):
-    """
-    Path, that is enforced to be:
-    - parent of the last path segment is an existing directory
-    - it does not point to a dir
-    """
-
-    def __init__(
-        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
-    ) -> None:
-        super().__init__(source_value, parents=parents, object_path=object_path)
-        p = self._value.parent
-        if not p.exists() or not p.is_dir():
-            raise ValueError("path does not point inside an existing directory")
-        if self._value.is_dir():
-            raise ValueError("path points to a directory when we expected a file")
-
-
-class CheckedPath(UncheckedPath):
-    """
-    Like UncheckedPath, but the file path is checked for being valid. So no non-existent directories in the middle,
-    no symlink loops. This however means, that resolving of relative path happens while validating.
-    """
-
-    def __init__(
-        self, source_value: Any, parents: Tuple["UncheckedPath", ...] = tuple(), object_path: str = "/"
-    ) -> None:
-        super().__init__(source_value, parents=parents, object_path=object_path)
-        try:
-            self._value = self._value.resolve(strict=False)
-        except RuntimeError as e:
-            raise ValueError("Failed to resolve given file path. Is there a symlink loop?") from e
index bb9898e7bd005d665c738836e5c4184364ccdb49..5fba82eedede622a35c98e16216d828535ea39a8 100644 (file)
@@ -7,6 +7,7 @@ import pytest
 from pytest import raises
 
 from knot_resolver_manager.datamodel.types import (
+    Dir,
     DomainName,
     InterfaceName,
     InterfaceOptionalPort,
@@ -21,7 +22,6 @@ from knot_resolver_manager.datamodel.types import (
     SizeUnit,
     TimeUnit,
 )
-from knot_resolver_manager.datamodel.types import Dir
 from knot_resolver_manager.utils.modeling import BaseSchema