]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
datamodel/types: created DomanNameOptionalPort' type
authorAleš Mrázek <ales.mrazek@nic.cz>
Mon, 28 Jul 2025 09:49:07 +0000 (11:49 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Mon, 20 Oct 2025 11:56:03 +0000 (13:56 +0200)
This custom type allows use of values in the format <domain-name>[@<port>].

python/knot_resolver/datamodel/types/__init__.py
python/knot_resolver/datamodel/types/types.py
tests/manager/datamodel/types/test_custom_types.py

index 7e5cab417a7aedd8d25e27ad0c1fda9f792977c8..75cd88cc08cf5c08ce422e19371e4fae9dfe57c1 100644 (file)
@@ -3,6 +3,7 @@ from .files import AbsoluteDir, Dir, File, FilePath, ReadableFile, WritableDir,
 from .generic_types import ListOrItem
 from .types import (
     DomainName,
+    DomainNameOptionalPort,
     EscapedStr,
     EscapedStr32B,
     FloatNonNegative,
@@ -36,6 +37,7 @@ __all__ = [
     "PolicyFlagEnum",
     "DNSRecordTypeEnum",
     "DomainName",
+    "DomainNameOptionalPort",
     "EscapedStr",
     "EscapedStr32B",
     "FloatNonNegative",
index fb22169effa61a2e31870eaad61a4c5c39d6df84..b41d2cc72f3755ce56d63b09109d390d5540efb9 100644 (file)
@@ -296,6 +296,24 @@ class IPAddressOptionalPort(StrBase):
             raise ValueError(f"expected '<ip-address>[@<port>]', got '{parts}'.", object_path)
 
 
+class DomainNameOptionalPort(StrBase):
+    name: DomainName
+    port: Optional[PortNumber] = None
+
+    def __init__(self, source_value: Any, object_path: str = "/") -> None:
+        super().__init__(source_value)
+        parts = source_value.split("@")
+        if 0 < len(parts) < 3:
+            try:
+                self.name = DomainName(parts[0])
+            except ValueError as e:
+                raise ValueError(f"failed to parse domain name '{parts[0]}'.", object_path) from e
+            if len(parts) == 2:
+                self.port = PortNumber.from_str(parts[1], object_path)
+        else:
+            raise ValueError(f"expected '<domain-name>[@<port>]', got '{parts}'.", object_path)
+
+
 class IPv4Address(BaseValueType):
     _value: ipaddress.IPv4Address
 
index 744e9b132ee198e43c6fb8b811f2abec1dcd8aef..5d5d557a622d096dbe8e2c9154a201921771e6b8 100644 (file)
@@ -9,6 +9,7 @@ from pytest import raises
 from knot_resolver.datamodel.types import (
     Dir,
     DomainName,
+    DomainNameOptionalPort,
     EscapedStr,
     InterfaceName,
     InterfaceOptionalPort,
@@ -261,6 +262,21 @@ def test_ip_address_optional_port_invalid(val: Any):
         IPAddressOptionalPort(val)
 
 
+@pytest.mark.parametrize("val", ["localhost", "localhost@5353"])
+def test_domain_name_optional_port_valid(val: str):
+    o = DomainNameOptionalPort(val)
+    assert str(o) == val
+    assert o == DomainNameOptionalPort(val)
+    assert str(o.name) == (val.split("@", 1)[0] if "@" in val else val)
+    assert o.port == (PortNumber(int(val.split("@", 1)[1])) if "@" in val else None)
+
+
+@pytest.mark.parametrize("val", ["localhost@", "@55"])
+def test_domain_name_optional_port_invalid(val: Any):
+    with raises(ValueError):
+        DomainNameOptionalPort(val)
+
+
 @pytest.mark.parametrize("val", ["123.4.5.6", "192.168.0.1"])
 def test_ipv4_address_valid(val: str):
     o = IPv4Address(val)