[Python-checkins] cpython: Issue #23133: Pickling of ipaddress objects now produces more compact and

serhiy.storchaka python-checkins at python.org
Sun Jan 18 21:37:26 CET 2015


https://hg.python.org/cpython/rev/781b54f7bccc
changeset:   94212:781b54f7bccc
parent:      94210:15f46b850257
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Sun Jan 18 22:36:33 2015 +0200
summary:
  Issue #23133: Pickling of ipaddress objects now produces more compact and
portable representation.

files:
  Lib/ipaddress.py           |  21 +++++++++++-----
  Lib/test/test_ipaddress.py |  31 ++++++++++++++++++++-----
  Misc/NEWS                  |   3 ++
  3 files changed, 41 insertions(+), 14 deletions(-)


diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -567,6 +567,9 @@
         except ValueError:
             cls._report_invalid_netmask(ip_str)
 
+    def __reduce__(self):
+        return self.__class__, (str(self),)
+
 
 class _BaseAddress(_IPAddressBase):
 
@@ -576,11 +579,6 @@
     used by single IP addresses.
     """
 
-    def __init__(self, address):
-        if (not isinstance(address, bytes)
-            and '/' in str(address)):
-            raise AddressValueError("Unexpected '/' in %r" % address)
-
     def __int__(self):
         return self._ip
 
@@ -626,6 +624,9 @@
     def _get_address_key(self):
         return (self._version, self)
 
+    def __reduce__(self):
+        return self.__class__, (self._ip,)
+
 
 class _BaseNetwork(_IPAddressBase):
 
@@ -1295,7 +1296,6 @@
             AddressValueError: If ipaddress isn't a valid IPv4 address.
 
         """
-        _BaseAddress.__init__(self, address)
         _BaseV4.__init__(self, address)
 
         # Efficient constructor from integer.
@@ -1313,6 +1313,8 @@
         # Assume input argument to be string or any object representation
         # which converts into a formatted IP string.
         addr_str = str(address)
+        if '/' in addr_str:
+            raise AddressValueError("Unexpected '/' in %r" % address)
         self._ip = self._ip_int_from_string(addr_str)
 
     @property
@@ -1446,6 +1448,8 @@
     def __hash__(self):
         return self._ip ^ self._prefixlen ^ int(self.network.network_address)
 
+    __reduce__ = _IPAddressBase.__reduce__
+
     @property
     def ip(self):
         return IPv4Address(self._ip)
@@ -1920,7 +1924,6 @@
             AddressValueError: If address isn't a valid IPv6 address.
 
         """
-        _BaseAddress.__init__(self, address)
         _BaseV6.__init__(self, address)
 
         # Efficient constructor from integer.
@@ -1938,6 +1941,8 @@
         # Assume input argument to be string or any object representation
         # which converts into a formatted IP string.
         addr_str = str(address)
+        if '/' in addr_str:
+            raise AddressValueError("Unexpected '/' in %r" % address)
         self._ip = self._ip_int_from_string(addr_str)
 
     @property
@@ -2134,6 +2139,8 @@
     def __hash__(self):
         return self._ip ^ self._prefixlen ^ int(self.network.network_address)
 
+    __reduce__ = _IPAddressBase.__reduce__
+
     @property
     def ip(self):
         return IPv6Address(self._ip)
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -8,6 +8,7 @@
 import re
 import contextlib
 import operator
+import pickle
 import ipaddress
 
 
@@ -82,6 +83,13 @@
         self.assertRaises(TypeError, hex, self.factory(1))
         self.assertRaises(TypeError, bytes, self.factory(1))
 
+    def pickle_test(self, addr):
+        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+            with self.subTest(proto=proto):
+                x = self.factory(addr)
+                y = pickle.loads(pickle.dumps(x, proto))
+                self.assertEqual(y, x)
+
 
 class CommonTestMixin_v4(CommonTestMixin):
 
@@ -247,6 +255,9 @@
         assertBadOctet("257.0.0.0", 257)
         assertBadOctet("192.168.0.999", 999)
 
+    def test_pickle(self):
+        self.pickle_test('192.0.2.1')
+
 
 class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6):
     factory = ipaddress.IPv6Address
@@ -379,6 +390,9 @@
         assertBadPart("02001:db8::", "02001")
         assertBadPart('2001:888888::1', "888888")
 
+    def test_pickle(self):
+        self.pickle_test('2001:db8::')
+
 
 class NetmaskTestMixin_v4(CommonTestMixin_v4):
     """Input validation on interfaces and networks is very similar"""
@@ -446,6 +460,11 @@
 class InterfaceTestCase_v4(BaseTestCase, NetmaskTestMixin_v4):
     factory = ipaddress.IPv4Interface
 
+    def test_pickle(self):
+        self.pickle_test('192.0.2.0/27')
+        self.pickle_test('192.0.2.0/31')  # IPV4LENGTH - 1
+        self.pickle_test('192.0.2.0')     # IPV4LENGTH
+
 
 class NetworkTestCase_v4(BaseTestCase, NetmaskTestMixin_v4):
     factory = ipaddress.IPv4Network
@@ -500,6 +519,11 @@
         assertBadNetmask("::1", "pudding")
         assertBadNetmask("::", "::")
 
+    def test_pickle(self):
+        self.pickle_test('2001:db8::1000/124')
+        self.pickle_test('2001:db8::1000/127')  # IPV6LENGTH - 1
+        self.pickle_test('2001:db8::1000')      # IPV6LENGTH
+
 
 class InterfaceTestCase_v6(BaseTestCase, NetmaskTestMixin_v6):
     factory = ipaddress.IPv6Interface
@@ -774,13 +798,6 @@
         self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128))
         self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network))
 
-    def testMissingAddressVersion(self):
-        class Broken(ipaddress._BaseAddress):
-            pass
-        broken = Broken('127.0.0.1')
-        with self.assertRaisesRegex(NotImplementedError, "Broken.*version"):
-            broken.version
-
     def testMissingNetworkVersion(self):
         class Broken(ipaddress._BaseNetwork):
             pass
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -203,6 +203,9 @@
 Library
 -------
 
+- Issue #23133: Pickling of ipaddress objects now produces more compact and
+  portable representation.
+
 - Issue #23248: Update ssl error codes from latest OpenSSL git master.
 
 - Issue #23266: Much faster implementation of ipaddress.collapse_addresses()

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list