Skip to content

Commit c48a496

Browse files
author
David Groves
committed
Moved first_address and last_address to correct classes, and added network_address and subnet_router_anycast_address
1 parent f8d797f commit c48a496

File tree

1 file changed

+68
-57
lines changed

1 file changed

+68
-57
lines changed

Lib/ipaddress.py

Lines changed: 68 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def _collapse_addresses_internal(addresses):
294294
last = None
295295
for net in sorted(subnets.values()):
296296
if last is not None:
297-
# Since they are sorted, last.network_address <= net.network_address
297+
# Since they are sorted, last.first_address <= net.first_address
298298
# is a given.
299299
if last.last_address >= net.last_address:
300300
continue
@@ -338,7 +338,7 @@ def collapse_addresses(addresses):
338338
try:
339339
ips.append(ip.ip)
340340
except AttributeError:
341-
ips.append(ip.network_address)
341+
ips.append(ip.first_address)
342342
else:
343343
if nets and nets[-1].version != ip.version:
344344
raise TypeError("%s and %s are not of the same version" % (
@@ -676,7 +676,7 @@ def __repr__(self):
676676
return '%s(%r)' % (self.__class__.__name__, str(self))
677677

678678
def __str__(self):
679-
return '%s/%d' % (self.network_address, self.prefixlen)
679+
return '%s/%d' % (self.first_address, self.prefixlen)
680680

681681
def hosts(self):
682682
"""Generate Iterator over usable hosts in a network.
@@ -685,19 +685,19 @@ def hosts(self):
685685
or broadcast addresses.
686686
687687
"""
688-
network = int(self.network_address)
688+
network = int(self.first_address)
689689
last = int(self.last_address)
690690
for x in range(network + 1, last):
691691
yield self._address_class(x)
692692

693693
def __iter__(self):
694-
network = int(self.network_address)
694+
network = int(self.first_address)
695695
last = int(self.last_address)
696696
for x in range(network, last + 1):
697697
yield self._address_class(x)
698698

699699
def __getitem__(self, n):
700-
network = int(self.network_address)
700+
network = int(self.first_address)
701701
last = int(self.last_address)
702702
if n >= 0:
703703
if network + n > last:
@@ -715,22 +715,22 @@ def __lt__(self, other):
715715
if self.version != other.version:
716716
raise TypeError('%s and %s are not of the same version' % (
717717
self, other))
718-
if self.network_address != other.network_address:
719-
return self.network_address < other.network_address
718+
if self.first_address != other.first_address:
719+
return self.first_address < other.first_address
720720
if self.netmask != other.netmask:
721721
return self.netmask < other.netmask
722722
return False
723723

724724
def __eq__(self, other):
725725
try:
726726
return (self.version == other.version and
727-
self.network_address == other.network_address and
727+
self.first_address == other.first_address and
728728
int(self.netmask) == int(other.netmask))
729729
except AttributeError:
730730
return NotImplemented
731731

732732
def __hash__(self):
733-
return hash(int(self.network_address) ^ int(self.netmask))
733+
return hash(int(self.first_address) ^ int(self.netmask))
734734

735735
def __contains__(self, other):
736736
# always false if one is v4 and the other is v6.
@@ -742,35 +742,44 @@ def __contains__(self, other):
742742
# dealing with another address
743743
else:
744744
# address
745-
return other._ip & self.netmask._ip == self.network_address._ip
745+
return other._ip & self.netmask._ip == self.first_address._ip
746746

747747
def overlaps(self, other):
748748
"""Tell if self is partly contained in other."""
749-
return self.network_address in other or (
749+
return self.first_address in other or (
750750
self.last_address in other or (
751-
other.network_address in self or (
751+
other.first_address in self or (
752752
other.last_address in self)))
753753

754754
@functools.cached_property
755755
def hostmask(self):
756756
return self._address_class(int(self.netmask) ^ self._ALL_ONES)
757757

758+
@functools.cached_property
759+
def first_address(self):
760+
return self._address_class(int(self.network_address))
761+
762+
@functools.cached_property
763+
def last_address(self):
764+
return self._address_class(int(self.network_address) |
765+
int(self.hostmask))
766+
758767
@property
759768
def with_prefixlen(self):
760-
return '%s/%d' % (self.network_address, self._prefixlen)
769+
return '%s/%d' % (self.first_address, self._prefixlen)
761770

762771
@property
763772
def with_netmask(self):
764-
return '%s/%s' % (self.network_address, self.netmask)
773+
return '%s/%s' % (self.first_address, self.netmask)
765774

766775
@property
767776
def with_hostmask(self):
768-
return '%s/%s' % (self.network_address, self.hostmask)
777+
return '%s/%s' % (self.first_address, self.hostmask)
769778

770779
@property
771780
def num_addresses(self):
772781
"""Number of hosts in the current subnet."""
773-
return int(self.last_address) - int(self.network_address) + 1
782+
return int(self.last_address) - int(self.first_address) + 1
774783

775784
@property
776785
def _address_class(self):
@@ -833,7 +842,7 @@ def address_exclude(self, other):
833842
return
834843

835844
# Make sure we're comparing the network of other.
836-
other = other.__class__('%s/%s' % (other.network_address,
845+
other = other.__class__('%s/%s' % (other.first_address,
837846
other.prefixlen))
838847

839848
s1, s2 = self.subnets()
@@ -896,11 +905,11 @@ def compare_networks(self, other):
896905
raise TypeError('%s and %s are not of the same type' % (
897906
self, other))
898907
# self.version == other.version below here:
899-
if self.network_address < other.network_address:
908+
if self.first_address < other.first_address:
900909
return -1
901-
if self.network_address > other.network_address:
910+
if self.first_address > other.first_address:
902911
return 1
903-
# self.network_address == other.network_address below here:
912+
# self.first_address == other.first_address below here:
904913
if self.netmask < other.netmask:
905914
return -1
906915
if self.netmask > other.netmask:
@@ -915,7 +924,7 @@ def _get_networks_key(self):
915924
and list.sort().
916925
917926
"""
918-
return (self.version, self.network_address, self.netmask)
927+
return (self.version, self.first_address, self.netmask)
919928

920929
def subnets(self, prefixlen_diff=1, new_prefix=None):
921930
"""The subnets which join to make the current subnet.
@@ -963,7 +972,7 @@ def subnets(self, prefixlen_diff=1, new_prefix=None):
963972
'prefix length diff %d is invalid for netblock %s' % (
964973
new_prefixlen, self))
965974

966-
start = int(self.network_address)
975+
start = int(self.first_address)
967976
end = int(self.last_address) + 1
968977
step = (int(self.hostmask) + 1) >> prefixlen_diff
969978
for new_addr in range(start, end, step):
@@ -1007,7 +1016,7 @@ def supernet(self, prefixlen_diff=1, new_prefix=None):
10071016
'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
10081017
(self.prefixlen, prefixlen_diff))
10091018
return self.__class__((
1010-
int(self.network_address) & (int(self.netmask) << prefixlen_diff),
1019+
int(self.first_address) & (int(self.netmask) << prefixlen_diff),
10111020
new_prefixlen
10121021
))
10131022

@@ -1020,7 +1029,7 @@ def is_multicast(self):
10201029
See RFC 2373 2.7 for details.
10211030
10221031
"""
1023-
return (self.network_address.is_multicast and
1032+
return (self.first_address.is_multicast and
10241033
self.last_address.is_multicast)
10251034

10261035
@staticmethod
@@ -1029,7 +1038,7 @@ def _is_subnet_of(a, b):
10291038
# Always false if one is v4 and the other is v6.
10301039
if a.version != b.version:
10311040
raise TypeError(f"{a} and {b} are not of the same version")
1032-
return (b.network_address <= a.network_address and
1041+
return (b.first_address <= a.first_address and
10331042
b.last_address >= a.last_address)
10341043
except AttributeError:
10351044
raise TypeError(f"Unable to test subnet containment "
@@ -1052,7 +1061,7 @@ def is_reserved(self):
10521061
reserved IPv6 Network ranges.
10531062
10541063
"""
1055-
return (self.network_address.is_reserved and
1064+
return (self.first_address.is_reserved and
10561065
self.last_address.is_reserved)
10571066

10581067
@property
@@ -1063,7 +1072,7 @@ def is_link_local(self):
10631072
A boolean, True if the address is reserved per RFC 4291.
10641073
10651074
"""
1066-
return (self.network_address.is_link_local and
1075+
return (self.first_address.is_link_local and
10671076
self.last_address.is_link_local)
10681077

10691078
@property
@@ -1075,10 +1084,10 @@ def is_private(self):
10751084
iana-ipv4-special-registry or iana-ipv6-special-registry.
10761085
10771086
"""
1078-
return any(self.network_address in priv_network and
1087+
return any(self.first_address in priv_network and
10791088
self.last_address in priv_network
10801089
for priv_network in self._constants._private_networks) and all(
1081-
self.network_address not in network and
1090+
self.first_address not in network and
10821091
self.last_address not in network
10831092
for network in self._constants._private_networks_exceptions
10841093
)
@@ -1103,7 +1112,7 @@ def is_unspecified(self):
11031112
RFC 2373 2.5.2.
11041113
11051114
"""
1106-
return (self.network_address.is_unspecified and
1115+
return (self.first_address.is_unspecified and
11071116
self.last_address.is_unspecified)
11081117

11091118
@property
@@ -1115,7 +1124,7 @@ def is_loopback(self):
11151124
RFC 2373 2.5.3.
11161125
11171126
"""
1118-
return (self.network_address.is_loopback and
1127+
return (self.first_address.is_loopback and
11191128
self.last_address.is_loopback)
11201129

11211130

@@ -1452,7 +1461,7 @@ def __lt__(self, other):
14521461
return False
14531462

14541463
def __hash__(self):
1455-
return hash((self._ip, self._prefixlen, int(self.network.network_address)))
1464+
return hash((self._ip, self._prefixlen, int(self.network.first_address)))
14561465

14571466
__reduce__ = _IPAddressBase.__reduce__
14581467

@@ -1481,7 +1490,7 @@ class IPv4Network(_BaseV4, _BaseNetwork):
14811490
"""This class represents and manipulates 32-bit IPv4 network + addresses..
14821491
14831492
Attributes: [examples for IPv4Network('192.0.2.0/27')]
1484-
.network_address: IPv4Address('192.0.2.0')
1493+
.first_address: IPv4Address('192.0.2.0')
14851494
.hostmask: IPv4Address('0.0.0.31')
14861495
.broadcast_address: IPv4Address('192.0.2.32')
14871496
.netmask: IPv4Address('255.255.255.224')
@@ -1528,14 +1537,14 @@ def __init__(self, address, strict=True):
15281537
"""
15291538
addr, mask = self._split_addr_prefix(address)
15301539

1531-
self.network_address = IPv4Address(addr)
1540+
self.first_address = IPv4Address(addr)
15321541
self.netmask, self._prefixlen = self._make_netmask(mask)
1533-
packed = int(self.network_address)
1542+
packed = int(self.first_address)
15341543
if packed & int(self.netmask) != packed:
15351544
if strict:
15361545
raise ValueError('%s has host bits set' % self)
15371546
else:
1538-
self.network_address = IPv4Address(packed &
1547+
self.first_address = IPv4Address(packed &
15391548
int(self.netmask))
15401549

15411550
if self._prefixlen == (self.max_prefixlen - 1):
@@ -1553,19 +1562,17 @@ def is_global(self):
15531562
iana-ipv4-special-registry.
15541563
15551564
"""
1556-
return (not (self.network_address in IPv4Network('100.64.0.0/10') and
1565+
return (not (self.first_address in IPv4Network('100.64.0.0/10') and
15571566
self.broadcast_address in IPv4Network('100.64.0.0/10')) and
15581567
not self.is_private)
15591568

1560-
@functools.cached_property
1561-
def last_address(self):
1562-
return self._address_class(int(self.network_address) |
1563-
int(self.hostmask))
1564-
15651569
@functools.cached_property
15661570
def broadcast_address(self):
15671571
return self.last_address
15681572

1573+
@functools.cached_property
1574+
def network_address(self):
1575+
return self.first_address
15691576

15701577
class _IPv4Constants:
15711578
_linklocal_network = IPv4Network('169.254.0.0/16')
@@ -1861,7 +1868,7 @@ def _explode_shorthand_ip_string(self):
18611868
18621869
"""
18631870
if isinstance(self, IPv6Network):
1864-
ip_str = str(self.network_address)
1871+
ip_str = str(self.first_address)
18651872
elif isinstance(self, IPv6Interface):
18661873
ip_str = str(self.ip)
18671874
else:
@@ -2238,7 +2245,7 @@ def __lt__(self, other):
22382245
return False
22392246

22402247
def __hash__(self):
2241-
return hash((self._ip, self._prefixlen, int(self.network.network_address)))
2248+
return hash((self._ip, self._prefixlen, int(self.network.first_address)))
22422249

22432250
__reduce__ = _IPAddressBase.__reduce__
22442251

@@ -2275,7 +2282,7 @@ class IPv6Network(_BaseV6, _BaseNetwork):
22752282
"""This class represents and manipulates 128-bit IPv6 networks.
22762283
22772284
Attributes: [examples for IPv6('2001:db8::1000/124')]
2278-
.network_address: IPv6Address('2001:db8::1000')
2285+
.first_address: IPv6Address('2001:db8::1000')
22792286
.hostmask: IPv6Address('::f')
22802287
.last_address: IPv6Address('2001:db8::100f')
22812288
.netmask: IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0')
@@ -2319,14 +2326,14 @@ def __init__(self, address, strict=True):
23192326
"""
23202327
addr, mask = self._split_addr_prefix(address)
23212328

2322-
self.network_address = IPv6Address(addr)
2329+
self.first_address = IPv6Address(addr)
23232330
self.netmask, self._prefixlen = self._make_netmask(mask)
2324-
packed = int(self.network_address)
2331+
packed = int(self.first_address)
23252332
if packed & int(self.netmask) != packed:
23262333
if strict:
23272334
raise ValueError('%s has host bits set' % self)
23282335
else:
2329-
self.network_address = IPv6Address(packed &
2336+
self.first_address = IPv6Address(packed &
23302337
int(self.netmask))
23312338

23322339
if self._prefixlen == (self.max_prefixlen - 1):
@@ -2341,7 +2348,7 @@ def hosts(self):
23412348
Subnet-Router anycast address.
23422349
23432350
"""
2344-
network = int(self.network_address)
2351+
network = int(self.first_address)
23452352
last = int(self.last_address)
23462353
for x in range(network + 1, last + 1):
23472354
yield self._address_class(x)
@@ -2358,21 +2365,25 @@ def is_site_local(self):
23582365
A boolean, True if the address is reserved per RFC 3513 2.5.6.
23592366
23602367
"""
2361-
return (self.network_address.is_site_local and
2368+
return (self.first_address.is_site_local and
23622369
self.last_address.is_site_local)
23632370

2364-
@property
2365-
def last_address(self):
2366-
"""The last address in the network, the address with all the host bits set."""
2367-
return self._address_class(int(self.network_address) |
2368-
int(self.hostmask))
2371+
@functools.cached_property
2372+
def subnet_router_anycast_address(self):
2373+
return self.first_address
23692374

2370-
@property
2375+
@functools.cached_property
2376+
@warnings.deprecated("IPv6 has no network addresses, use first_address or subnet_router_anycast_address instead.")
2377+
def network_address(self):
2378+
return self.first_address
2379+
2380+
@functools.cached_property
23712381
@warnings.deprecated("IPv6 has no broadcast addresses, use last_address instead for the address with all the host bits set.")
23722382
def broadcast_address(self):
23732383
return self.last_address
23742384

23752385

2386+
23762387
class _IPv6Constants:
23772388

23782389
_linklocal_network = IPv6Network('fe80::/10')

0 commit comments

Comments
 (0)