@@ -1119,6 +1119,50 @@ def is_loopback(self):
11191119 return (self .network_address .is_loopback and
11201120 self .broadcast_address .is_loopback )
11211121
1122+ def _network_by_offset (self , prefix , offset ):
1123+ """Get the network offset from this network.
1124+
1125+ Args:
1126+ prefix: Target prefix length.
1127+ offset: Number of networks to move (+1 or -1).
1128+
1129+ Returns:
1130+ An IPv(4|6) Network object.
1131+
1132+ """
1133+ if prefix < 1 or prefix > self .max_prefixlen :
1134+ raise ValueError (
1135+ f"prefix must be between 1 and { self .max_prefixlen } "
1136+ )
1137+ new_netmask , _ = self ._make_netmask (prefix )
1138+ error = f"out of address space, cannot make another /{ prefix } network"
1139+
1140+ if prefix > self .prefixlen :
1141+ if offset < 0 :
1142+ new_ip = self .network_address ._ip - 1
1143+ else :
1144+ new_ip = self .broadcast_address ._ip + 1
1145+ if new_ip < 0 or new_ip > self ._ALL_ONES :
1146+ raise ValueError (error )
1147+
1148+ new_ip &= new_netmask ._ip
1149+ else :
1150+ bit_shift = self .max_prefixlen - prefix
1151+ new_ip = (
1152+ ((new_netmask ._ip & self .network_address ._ip ) >> bit_shift )
1153+ + offset
1154+ ) << bit_shift
1155+
1156+ if new_ip < 0 :
1157+ raise ValueError (error )
1158+
1159+ try :
1160+ return self .__class__ (
1161+ f"{ self ._string_from_ip_int (new_ip )} /{ prefix } "
1162+ )
1163+ except OverflowError :
1164+ raise ValueError (error ) from None
1165+
11221166 def next_network (self , next_prefix = None ):
11231167 """Get the next closest network with a specific prefix.
11241168
@@ -1132,33 +1176,25 @@ def next_network(self, next_prefix=None):
11321176 """
11331177 if next_prefix is None :
11341178 next_prefix = self .prefixlen
1135- new_netmask = self .netmask
1136- else :
1137- if next_prefix < 1 or next_prefix > self .max_prefixlen :
1138- raise ValueError (
1139- f"next prefix must be between 1 and { self .max_prefixlen } "
1140- )
1141- new_netmask , _ = self ._make_netmask (next_prefix )
11421179
1143- bit_shift = (
1144- self .max_prefixlen - next_prefix
1145- if next_prefix <= self .prefixlen
1146- else self .max_prefixlen - self .prefixlen
1147- )
1180+ return self ._network_by_offset (next_prefix , 1 )
11481181
1149- next_ip = (
1150- ((new_netmask ._ip & self .network_address ._ip ) >> bit_shift ) + 1
1151- ) << bit_shift
11521182
1153- try :
1154- return self .__class__ (
1155- f"{ self ._string_from_ip_int (next_ip )} /{ next_prefix } "
1156- )
1157- except OverflowError :
1158- raise ValueError (
1159- f"out of address space, cannot make another /{ next_prefix } "
1160- "network"
1161- ) from None
1183+ def prev_network (self , prev_prefix = None ):
1184+ """Get the previous closest network with a specific prefix.
1185+
1186+ Args:
1187+ prev_prefix: The desired previous prefix length, if not specified the
1188+ same self.prefixlen will be used
1189+
1190+ Returns:
1191+ An IPv(4|6) Network object of the previous closest network.
1192+
1193+ """
1194+ if prev_prefix is None :
1195+ prev_prefix = self .prefixlen
1196+
1197+ return self ._network_by_offset (prev_prefix , - 1 )
11621198
11631199
11641200class _BaseConstants :
0 commit comments