[issue32974] Add bitwise operations and other missing comparison methods to Python's IP address module

Kyle Agronick report at bugs.python.org
Wed Feb 28 20:13:29 EST 2018


New submission from Kyle Agronick <agronick at gmail.com>:

I've recently had the experience of implementing a system for managing DNS records at a Fortune 10 company with ~10,000 stores. There were a number of things that I felt were missing from the IP address module and could be added without introducing any breaking changes.

The easiest changes I saw would be to implement bitwise operations without casting all the addresses to ints and then back to IP addresses.

Lets say you wanted to take the last octet from one address and put it on another:

Right now you need to do:
IPv6Address(int(v6('2001:db8:85a3:0:0:8a2e:370:7334')) & int(IPv6Address('0:0:0:0:0:0:0:ffff')) | int(IPv6Address('1323:cf3:23df:0:0:32:44:0')))
# returns IPv6Address('1323:cf3:23df::32:44:7334')

You should be able to do:
(IPv6Address('2001:db8:85a3:0:0:8a2e:370:7334') & IPv6Address('0:0:0:0:0:0:0:ffff')) | IPv6Address('1323:cf3:23df:0:0:32:44:0')
# returns TypeError: unsupported operand type(s) for &: 'IPv6Address' and 'IPv6Address'

All that would be required is to do the casting to int automatically.

The other thing I saw that I would like would be to override the methods that return generators with iterables that provide more comparison operations.

Right now you can check if an IP is in a network with:
IPv4Address('192.168.1.12') in IPv4Network('192.168.1.0/24') 
# returns True

You should be able to do this with methods that return multiple networks.
ipaddress.summarize_address_range() is a method that returns a generator of IPv(4|6)Networks.

To see if an IP address is in one of multiple networks you need to do:
any(map(lambda i: IPv4Address('192.168.1.12') in i, ipaddress.summarize_address_range(IPv4Address('192.168.1.0'), IPv4Address('192.168.2.255'))))
# returns True

You should be able to do:
IPv4Address('192.168.1.12') in ipaddress.summarize_address_range(IPv4Address('192.168.1.0'), IPv4Address('192.168.2.255'))
# returns False

This should be the default for IPv(4|6)Addresses. IPv(4|6)Networks should check membership like they currently do.

You should be able to subtract ranges to make ranges that include some IPs but not others:
ipaddress.summarize_address_range(IPv4Address('192.168.1.0'), IPv4Address('192.168.2.255')) - ipaddress.summarize_address_range(IPv4Address('192.168.1.20'), IPv4Address('192.168.1.50'))
# returns TypeError: unsupported operand type(s) for -: 'generator' and 'generator'

This should return a iterable that has networks that include 192.168.1.0 to 192.168.1.20 and 192.168.1.50 to 192.168.2.255.

You should be able to do addition as well without casting to a list.

Methods like .hosts() should be able to be performed on the iterator instead of doing:
sum([list(i.hosts()) for i in ipaddress.summarize_address_range(IPv4Address('192.168.1.0'), IPv4Address('192.168.2.255'))], [])

do:
ipaddress.summarize_address_range(IPv4Address('192.168.1.0'), IPv4Address('192.168.2.255')).hosts()

Another great feature would be to allow division on networks and network generators giving you every xth host:
(i for i in IPv4Network('192.168.1.0/24').hosts() if int(i) % x == 0)

When x is 32 you get:
IPv4Address('192.168.1.32'), 
IPv4Address('192.168.1.64'), 
IPv4Address('192.168.1.96'), 
IPv4Address('192.168.1.128'), 
IPv4Address('192.168.1.160'), 
IPv4Address('192.168.1.192'), 
IPv4Address('192.168.1.224')

I would be happy to code this if the consensus was that this would be included.

----------
components: Library (Lib)
messages: 313077
nosy: Kyle Agronick
priority: normal
severity: normal
status: open
title: Add bitwise operations and other missing comparison methods to Python's IP address module
type: enhancement
versions: Python 3.8

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue32974>
_______________________________________


More information about the Python-bugs-list mailing list