Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions netutils/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ipaddress
import typing as t
from operator import attrgetter
from operator import attrgetter, methodcaller

from netutils.constants import IPV4_MASKS, IPV6_MASKS

Expand Down Expand Up @@ -60,12 +60,13 @@ def ipaddress_interface(ip: str, attr: str) -> t.Any:
return retrieved_method


def ipaddress_network(ip: str, attr: str) -> t.Any:
def ipaddress_network(ip: str, attr: str, **kwargs: t.Any) -> t.Any:
"""Convenience function primarily built to expose ipaddress.ip_network to Jinja.

Args:
ip: IP network str compliant with ipaddress.ip_network inputs.
attr: An attribute in string dotted format.
kwargs: Keyword arguments to pass along to the given method of ipaddress.ip_network.

Returns:
Returns the value provided by the ipaddress.ip_network attribute provided.
Expand All @@ -76,9 +77,14 @@ def ipaddress_network(ip: str, attr: str) -> t.Any:
4
>>> ipaddress_network('10.1.1.0/24', '__str__')
'10.1.1.0/24'
>>>
>>> list(ipaddress_network('192.168.1.0/28', 'subnets', new_prefix=30))
[IPv4Network('192.168.1.0/30'), IPv4Network('192.168.1.4/30'), IPv4Network('192.168.1.8/30'), IPv4Network('192.168.1.12/30')]
"""
retriever = attrgetter(attr)
retriever: t.Callable[[t.Union[ipaddress.IPv4Network, ipaddress.IPv6Network]], t.Any]
if kwargs:
retriever = methodcaller(attr, **kwargs)
else:
retriever = attrgetter(attr)
retrieved_method = retriever(ipaddress.ip_network(ip))
if callable(retrieved_method):
return retrieved_method()
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/test_ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@
},
]

IP_NETWORK_WITH_KWARGS = [
{
"sent": {"ip": "10.1.1.0/28", "attr": "subnets", "new_prefix": 30},
"received": "[IPv4Network('10.1.1.0/30'), IPv4Network('10.1.1.4/30'), IPv4Network('10.1.1.8/30'), IPv4Network('10.1.1.12/30')]",
},
{
"sent": {"ip": "10.1.1.0/28", "attr": "subnets"},
"received": "[IPv4Network('10.1.1.0/29'), IPv4Network('10.1.1.8/29')]",
},
]

IP_NETWORK = [
{
"sent": {"ip": "10.1.1.0/24", "attr": "hostmask.__str__"},
Expand Down Expand Up @@ -658,6 +669,11 @@ def test_ipaddress_network(data):
assert ip.ipaddress_network(**data["sent"]) == data["received"]


@pytest.mark.parametrize("data", IP_NETWORK_WITH_KWARGS)
def test_ipaddress_network_with_kwargs(data):
assert str(list(ip.ipaddress_network(**data["sent"]))) == data["received"]


@pytest.mark.parametrize("data", IS_CLASSFUL)
def test_is_classful(data):
assert ip.is_classful(**data["sent"]) == data["received"]
Expand Down