Expose ipaddress constants to public API

The ipaddress module defines several ‘private’ constants derived from the IANA Special Purpose Address Registries [1][2]. The module uses these to implement several functions on Address and Network objects, (e.g. is_private).

As these are already defined in the module as ipaddress objects, it feels sensible to expose them as part of the public API to allow users of the library to benefit from a consistent definition of constants - especially as it is not completely clear how each constant maps to the IANA specification.

Exposing these should be as simple as removing underscores as necessary, and providing the appropriate documentation and testing.

For reference, the constants under discussion are:

class _IPv4Constants:
    _linklocal_network = IPv4Network('169.254.0.0/16')

    _loopback_network = IPv4Network('127.0.0.0/8')

    _multicast_network = IPv4Network('224.0.0.0/4')

    _public_network = IPv4Network('100.64.0.0/10')

    _private_networks = [
        IPv4Network('0.0.0.0/8'),
        IPv4Network('10.0.0.0/8'),
        IPv4Network('127.0.0.0/8'),
        IPv4Network('169.254.0.0/16'),
        IPv4Network('172.16.0.0/12'),
        IPv4Network('192.0.0.0/29'),
        IPv4Network('192.0.0.170/31'),
        IPv4Network('192.0.2.0/24'),
        IPv4Network('192.168.0.0/16'),
        IPv4Network('198.18.0.0/15'),
        IPv4Network('198.51.100.0/24'),
        IPv4Network('203.0.113.0/24'),
        IPv4Network('240.0.0.0/4'),
        IPv4Network('255.255.255.255/32'),
        ]

    _reserved_network = IPv4Network('240.0.0.0/4')

    _unspecified_address = IPv4Address('0.0.0.0')

and

class _IPv6Constants:

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

    _multicast_network = IPv6Network('ff00::/8')

    _private_networks = [
        IPv6Network('::1/128'),
        IPv6Network('::/128'),
        IPv6Network('::ffff:0:0/96'),
        IPv6Network('100::/64'),
        IPv6Network('2001::/23'),
        IPv6Network('2001:2::/48'),
        IPv6Network('2001:db8::/32'),
        IPv6Network('2001:10::/28'),
        IPv6Network('fc00::/7'),
        IPv6Network('fe80::/10'),
        ]

    _reserved_networks = [
        IPv6Network('::/8'), IPv6Network('100::/8'),
        IPv6Network('200::/7'), IPv6Network('400::/6'),
        IPv6Network('800::/5'), IPv6Network('1000::/4'),
        IPv6Network('4000::/3'), IPv6Network('6000::/3'),
        IPv6Network('8000::/3'), IPv6Network('A000::/3'),
        IPv6Network('C000::/3'), IPv6Network('E000::/4'),
        IPv6Network('F000::/5'), IPv6Network('F800::/6'),
        IPv6Network('FE00::/9'),
    ]

    _sitelocal_network = IPv6Network('fec0::/10')

Hi Pete.

How will users benefit from a consistent definition of constants?

In other words, why (for what purpose) will users use those constants instead of the functions already defined?

Hi,

While the methods allow checking an existing object after creating it, there are use cases where it is beneficial to directly access the defined list.
For example, generating addresses that should not be routed, or for avoiding “magic numbers” when referring to certain address blocks.

Of course this is all possible at the moment but not without redefinition or accessing private member’s of the module.

Are the use cases common enough? As you say, if you get over your worry about accessing a private member, there’s no problem.

Although I have desired this in my own code, I’m not sure I can speak for how many others have required this.
Accessing the private members works (albeit making the code less ‘clean’); but generally the worry comes from the lack of agreement that the values won’t change without warning when accessing non public members. That should not be the case in this instance however, unless a new RFC adds or changes any special ranges.

While the advantage of keeping these private is that it’s one less thing to maintain and document, I would challenge that this is relatively straightforward as we can refer to the existing IANA documentation and how it is derived.

It may be that this use case is too niche to justify the suggestion, but in terms of code change and maintenance overhead it feels like a reasonably quick and easy win that may benefit others.