Skip to content

Commit ab61999

Browse files
committed
add treatment for network types
1 parent d193330 commit ab61999

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

src/serializers/infer.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,13 @@ pub(crate) fn infer_to_python_known<'py>(
167167
let either_delta = EitherTimedelta::try_from(value)?;
168168
state.config.temporal_mode.timedelta_to_json(value.py(), either_delta)?
169169
}
170-
ObType::Url | ObType::MultiHostUrl | ObType::Path | ObType::Ipv4Address | ObType::Ipv6Address => {
171-
serialize_via_str(value, serialize_to_python())?
172-
}
170+
ObType::Url
171+
| ObType::MultiHostUrl
172+
| ObType::Path
173+
| ObType::Ipv4Address
174+
| ObType::Ipv6Address
175+
| ObType::Ipv4Network
176+
| ObType::Ipv6Network => serialize_via_str(value, serialize_to_python())?,
173177
ObType::Uuid => {
174178
let uuid = super::type_serializers::uuid::uuid_to_string(value)?;
175179
uuid.into_py_any(py)?
@@ -414,9 +418,13 @@ pub(crate) fn infer_serialize_known<'py, S: Serializer>(
414418
let either_delta = EitherTimedelta::try_from(value).map_err(py_err_se_err)?;
415419
state.config.temporal_mode.timedelta_serialize(either_delta, serializer)
416420
}
417-
ObType::Url | ObType::MultiHostUrl | ObType::Path | ObType::Ipv4Address | ObType::Ipv6Address => {
418-
serialize_via_str(value, serialize_to_json(serializer)).map_err(unwrap_ser_error)
419-
}
421+
ObType::Url
422+
| ObType::MultiHostUrl
423+
| ObType::Path
424+
| ObType::Ipv4Address
425+
| ObType::Ipv6Address
426+
| ObType::Ipv4Network
427+
| ObType::Ipv6Network => serialize_via_str(value, serialize_to_json(serializer)).map_err(unwrap_ser_error),
420428
ObType::PydanticSerializable => {
421429
call_pydantic_serializer(value, state, serialize_to_json(serializer)).map_err(unwrap_ser_error)
422430
}
@@ -547,7 +555,13 @@ pub(crate) fn infer_json_key_known<'a, 'py>(
547555
let either_delta = EitherTimedelta::try_from(key)?;
548556
state.config.temporal_mode.timedelta_json_key(&either_delta)
549557
}
550-
ObType::Url | ObType::MultiHostUrl | ObType::Path | ObType::Ipv4Address | ObType::Ipv6Address => {
558+
ObType::Url
559+
| ObType::MultiHostUrl
560+
| ObType::Path
561+
| ObType::Ipv4Address
562+
| ObType::Ipv6Address
563+
| ObType::Ipv4Network
564+
| ObType::Ipv6Network => {
551565
// FIXME it would be nice to have a "PyCow" which carries ownership of the Python type too
552566
Ok(Cow::Owned(key.str()?.to_string_lossy().into_owned()))
553567
}

src/serializers/ob_type.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub struct ObTypeLookup {
5353
// ip address types
5454
ipv4_address: Py<PyAny>,
5555
ipv6_address: Py<PyAny>,
56+
ipv4_network: Py<PyAny>,
57+
ipv6_network: Py<PyAny>,
5658
}
5759

5860
static TYPE_LOOKUP: PyOnceLock<ObTypeLookup> = PyOnceLock::new();
@@ -94,6 +96,8 @@ impl ObTypeLookup {
9496
complex: PyComplex::type_object_raw(py) as usize,
9597
ipv4_address: py.import("ipaddress").unwrap().getattr("IPv4Address").unwrap().unbind(),
9698
ipv6_address: py.import("ipaddress").unwrap().getattr("IPv6Address").unwrap().unbind(),
99+
ipv4_network: py.import("ipaddress").unwrap().getattr("IPv4Network").unwrap().unbind(),
100+
ipv6_network: py.import("ipaddress").unwrap().getattr("IPv6Network").unwrap().unbind(),
97101
}
98102
}
99103

@@ -166,6 +170,8 @@ impl ObTypeLookup {
166170
ObType::Complex => self.complex == ob_type,
167171
ObType::Ipv4Address => self.ipv4_address.as_ptr() as usize == ob_type,
168172
ObType::Ipv6Address => self.ipv6_address.as_ptr() as usize == ob_type,
173+
ObType::Ipv4Network => self.ipv4_network.as_ptr() as usize == ob_type,
174+
ObType::Ipv6Network => self.ipv6_network.as_ptr() as usize == ob_type,
169175
ObType::Unknown => false,
170176
};
171177

@@ -351,6 +357,10 @@ impl ObTypeLookup {
351357
ObType::Ipv4Address
352358
} else if value.is_instance(self.ipv6_address.bind(py)).unwrap_or(false) {
353359
ObType::Ipv6Address
360+
} else if value.is_instance(self.ipv4_network.bind(py)).unwrap_or(false) {
361+
ObType::Ipv4Network
362+
} else if value.is_instance(self.ipv6_network.bind(py)).unwrap_or(false) {
363+
ObType::Ipv6Network
354364
} else {
355365
ObType::Unknown
356366
}
@@ -437,6 +447,8 @@ pub enum ObType {
437447
// ip address types
438448
Ipv4Address,
439449
Ipv6Address,
450+
Ipv4Network,
451+
Ipv6Network,
440452
// unknown type
441453
Unknown,
442454
}

tests/serializers/test_any.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,16 +735,44 @@ def __str__(self):
735735
return super().__str__() + '_subclassed'
736736

737737

738+
class SubNetV4(ipaddress.IPv4Network):
739+
def __str__(self):
740+
return super().__str__() + '_subclassed'
741+
742+
743+
class SubNetV6(ipaddress.IPv6Network):
744+
def __str__(self):
745+
return super().__str__() + '_subclassed'
746+
747+
748+
class SubInterfaceV4(ipaddress.IPv4Interface):
749+
def __str__(self):
750+
return super().__str__() + '_subclassed'
751+
752+
753+
class SubInterfaceV6(ipaddress.IPv6Interface):
754+
def __str__(self):
755+
return super().__str__() + '_subclassed'
756+
757+
738758
@pytest.mark.parametrize(
739759
('value', 'expected_json'),
740760
[
741761
(ipaddress.IPv4Address('192.168.1.1'), '192.168.1.1'),
742762
(ipaddress.IPv6Address('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), '2001:db8:85a3::8a2e:370:7334'),
743763
(SubIpV4('192.168.1.1'), '192.168.1.1_subclassed'),
744764
(SubIpV6('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), '2001:db8:85a3::8a2e:370:7334_subclassed'),
765+
(ipaddress.IPv4Network('192.168.1.0/24'), '192.168.1.0/24'),
766+
(ipaddress.IPv6Network('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), '2001:db8:85a3::8a2e:370:7334/128'),
767+
(SubNetV4('192.168.1.0/24'), '192.168.1.0/24_subclassed'),
768+
(SubNetV6('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), '2001:db8:85a3::8a2e:370:7334/128_subclassed'),
769+
(ipaddress.IPv4Interface('192.168.1.1/24'), '192.168.1.1/24'),
770+
(ipaddress.IPv6Interface('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), '2001:db8:85a3::8a2e:370:7334/128'),
771+
(SubInterfaceV4('192.168.1.1/24'), '192.168.1.1/24_subclassed'),
772+
(SubInterfaceV6('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), '2001:db8:85a3::8a2e:370:7334/128_subclassed'),
745773
],
746774
)
747-
def test_ip_address_type_inference(any_serializer, value, expected_json):
775+
def test_ipaddress_type_inference(any_serializer, value, expected_json):
748776
assert any_serializer.to_python(value) == value
749777
assert any_serializer.to_python(value, mode='json') == expected_json
750778
assert any_serializer.to_json(value) == f'"{expected_json}"'.encode()

0 commit comments

Comments
 (0)