From 45ea3c62b798d8e3f2666de04e204b06e58c110b Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 11 Feb 2018 12:27:01 -0500 Subject: [PATCH 01/27] bits method and test_bits --- Lib/ipaddress.py | 10 ++++++++++ Lib/test/test_ipaddress.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index e8ce4cef2ded4b..485164813e3b3a 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1258,6 +1258,11 @@ def max_prefixlen(self): def version(self): return self._version + @property + def bits(self): + fstr = '0' + str(IPV4LENGTH) + 'b' + return '0b' + format(int(self), fstr) + class IPv4Address(_BaseV4, _BaseAddress): @@ -1890,6 +1895,11 @@ def max_prefixlen(self): def version(self): return self._version + @property + def bits(self): + fstr = '0' + str(IPV6LENGTH) + 'b' + return '0b' + format(int(self), fstr) + class IPv6Address(_BaseV6, _BaseAddress): diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index dbf68b3f8f1a06..fd6f13e88811b0 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -170,6 +170,11 @@ def assertBadLength(length): class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): factory = ipaddress.IPv4Address + def test_bits(self): + addr = "0.0.0.42" # because there are lots of left zeroes + addr_obj = ipaddress.IPv4Address(addr) + self.assertEqual(addr_obj.bits, '0b00000000000000000000000000101010') + def test_network_passed_as_address(self): addr = "127.0.0.1/24" with self.assertAddressError("Unexpected '/' in %r", addr): @@ -266,6 +271,16 @@ def test_weakref(self): class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): factory = ipaddress.IPv6Address + def test_bits(self): + addr = "1:0db8:85a3:0000:0000:8a2e:0370:7334" + addr_obj = ipaddress.IPv6Address(addr) + self.assertEqual(addr_obj.bits, + "0b00000000000000010000110110111000" + "10000101101000110000000000000000" + "00000000000000001000101000101110" + "00000011011100000111001100110100") + + def test_network_passed_as_address(self): addr = "::1/24" with self.assertAddressError("Unexpected '/' in %r", addr): From b470a10018c71d8e29cf01d24c367df80d998500 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 11 Feb 2018 12:36:05 -0500 Subject: [PATCH 02/27] Cleaned up assert string --- Lib/test/test_ipaddress.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index fd6f13e88811b0..ba8c0c28a4ff4f 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -274,7 +274,7 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): def test_bits(self): addr = "1:0db8:85a3:0000:0000:8a2e:0370:7334" addr_obj = ipaddress.IPv6Address(addr) - self.assertEqual(addr_obj.bits, + self.assertEqual(addr_obj.bits, "0b00000000000000010000110110111000" "10000101101000110000000000000000" "00000000000000001000101000101110" From 4c8af713f3f33d102f124e5da5690fb1f4561e1d Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 11 Feb 2018 12:42:08 -0500 Subject: [PATCH 03/27] blurb --- .../next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst diff --git a/Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst b/Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst new file mode 100644 index 00000000000000..399c5225e574ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst @@ -0,0 +1,2 @@ +Added bits() method to return the fully padded binary representation of an +IPv4 or IPv6 address. Test case included. From d1f97327969eb7ce8dc5473bfec265645a74eb58 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 11 Feb 2018 14:44:36 -0500 Subject: [PATCH 04/27] added docstring --- Lib/ipaddress.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 485164813e3b3a..506e737cc3a421 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1260,6 +1260,8 @@ def version(self): @property def bits(self): + """Returns the binary representation of the IPv4 address, padded to 32 + bits.""" fstr = '0' + str(IPV4LENGTH) + 'b' return '0b' + format(int(self), fstr) @@ -1897,6 +1899,8 @@ def version(self): @property def bits(self): + """Returns the binary representation of the IPv6 address, padded to 128 + bits.""" fstr = '0' + str(IPV6LENGTH) + 'b' return '0b' + format(int(self), fstr) From b72330d46a0c41157c5e9d12173b39ad3fa16699 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 11 Feb 2018 19:41:52 -0500 Subject: [PATCH 05/27] Faster method, per Eric Smith --- Lib/ipaddress.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 506e737cc3a421..5d00ae177568a0 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1262,8 +1262,7 @@ def version(self): def bits(self): """Returns the binary representation of the IPv4 address, padded to 32 bits.""" - fstr = '0' + str(IPV4LENGTH) + 'b' - return '0b' + format(int(self), fstr) + return f'{int(self):#0{IPV4LENGTH+2}b}' class IPv4Address(_BaseV4, _BaseAddress): @@ -1901,8 +1900,7 @@ def version(self): def bits(self): """Returns the binary representation of the IPv6 address, padded to 128 bits.""" - fstr = '0' + str(IPV6LENGTH) + 'b' - return '0b' + format(int(self), fstr) + return f'{int(self):#0{IPV6LENGTH+2}b}' class IPv6Address(_BaseV6, _BaseAddress): From 6c7d1a4de30c867dce5bbfb02311214933a3f974 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 13 Feb 2018 08:33:40 -0500 Subject: [PATCH 06/27] redoing as __format__ --- Lib/ipaddress.py | 49 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 5d00ae177568a0..ad843cced2732d 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1089,6 +1089,43 @@ class _BaseV4: def _explode_shorthand_ip_string(self): return str(self) + def __format__(self, fmt): + """Format: ends with b for bin, h for hex, n for native (bin for ipv4, + hex for ipv6). Takes # to include 0b, and _ as a separator + """ + if fmt[-1] in 'bnx': + fmt_base = fmt[-1] + if fmt_base == 'n': + fmt_base = 'b' # binary is default for ipv4 + + if '_' in fmt: + separator = '_' + else: + separator = '' + + # binary + if fmt_base == 'b': + # resulting string is '0b' + 32 bits + # plus 7 _ if needed + padlen = IPV4LENGTH+2 + (7*len(separator)) + + # hex + elif fmt_base == 'x': + # resulting string is '0x' + 8 hex digits + # plus a single _ if needed + padlen = int(IPV4LENGTH/4)+2 + len(separator) + + retstr = f'{int(self):#0{padlen}{separator}{fmt_base}}' + + # strip left two if necessary + if '#' not in fmt: + retstr = retstr[2:] + + else: + retstr = str(self) + + return retstr + @classmethod def _make_netmask(cls, arg): """Make a (netmask, prefix_len) tuple from the given argument. @@ -1258,12 +1295,6 @@ def max_prefixlen(self): def version(self): return self._version - @property - def bits(self): - """Returns the binary representation of the IPv4 address, padded to 32 - bits.""" - return f'{int(self):#0{IPV4LENGTH+2}b}' - class IPv4Address(_BaseV4, _BaseAddress): @@ -1896,12 +1927,6 @@ def max_prefixlen(self): def version(self): return self._version - @property - def bits(self): - """Returns the binary representation of the IPv6 address, padded to 128 - bits.""" - return f'{int(self):#0{IPV6LENGTH+2}b}' - class IPv6Address(_BaseV6, _BaseAddress): From 6a1d467556f97b371c9469fec193bba1ab8a3e15 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 13 Feb 2018 08:57:07 -0500 Subject: [PATCH 07/27] added ipv6 method --- Lib/ipaddress.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index ad843cced2732d..666141e85f0844 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1664,6 +1664,43 @@ class _BaseV6: # when constructed (see _make_netmask()). _netmask_cache = {} + def __format__(self, fmt): + """Format: ends with b for bin, h for hex, n for native (bin for ipv4, + hex for ipv6). Takes # to include 0b, and _ as a separator + """ + if fmt[-1] in 'bnx': + fmt_base = fmt[-1] + if fmt_base == 'n': + fmt_base = 'x' # hex is default for ipv4 + + if '_' in fmt: + separator = '_' + else: + separator = '' + + # binary + if fmt_base == 'b': + # resulting string is '0b' + 32 bits + # plus 7 _ if needed + padlen = IPV6LENGTH+2 + (31*len(separator)) + + # hex + elif fmt_base == 'x': + # resulting string is '0x' + 8 hex digits + # plus 7 single _ if needed + padlen = int(IPV6LENGTH/4)+2 + (7*len(separator)) + + retstr = f'{int(self):#0{padlen}{separator}{fmt_base}}' + + # strip left two if necessary + if '#' not in fmt: + retstr = retstr[2:] + + else: + retstr = str(self) + + return retstr + @classmethod def _make_netmask(cls, arg): """Make a (netmask, prefix_len) tuple from the given argument. From 41f637abe8338821427bbc8725e827b44478f94a Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 13 Feb 2018 12:15:19 -0500 Subject: [PATCH 08/27] test cases and cleanup --- Lib/ipaddress.py | 4 +-- Lib/test/test_ipaddress.py | 69 ++++++++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 666141e85f0844..3fef303588cb2f 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1093,7 +1093,7 @@ def __format__(self, fmt): """Format: ends with b for bin, h for hex, n for native (bin for ipv4, hex for ipv6). Takes # to include 0b, and _ as a separator """ - if fmt[-1] in 'bnx': + if len(fmt) and fmt[-1] in 'bnx': fmt_base = fmt[-1] if fmt_base == 'n': fmt_base = 'b' # binary is default for ipv4 @@ -1668,7 +1668,7 @@ def __format__(self, fmt): """Format: ends with b for bin, h for hex, n for native (bin for ipv4, hex for ipv6). Takes # to include 0b, and _ as a separator """ - if fmt[-1] in 'bnx': + if len(fmt) and fmt[-1] in 'bnx': fmt_base = fmt[-1] if fmt_base == 'n': fmt_base = 'x' # hex is default for ipv4 diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index ba8c0c28a4ff4f..8cce762230cee5 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -169,11 +169,27 @@ def assertBadLength(length): class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): factory = ipaddress.IPv4Address - - def test_bits(self): - addr = "0.0.0.42" # because there are lots of left zeroes - addr_obj = ipaddress.IPv4Address(addr) - self.assertEqual(addr_obj.bits, '0b00000000000000000000000000101010') + + def test_format(self): + addr = ipaddress.IPv4Address("1.2.3.4") + pairs = [ + ("b" ,"00000001000000100000001100000100"), + ("n" ,"00000001000000100000001100000100"), + ("x" ,"01020304"), + ("_b" ,"0000_0001_0000_0010_0000_0011_0000_0100"), + ("_n" ,"0000_0001_0000_0010_0000_0011_0000_0100"), + ("_x" ,"0102_0304"), + ("#b" ,"0b00000001000000100000001100000100"), + ("#n" ,"0b00000001000000100000001100000100"), + ("#x" ,"0x01020304"), + ("#_b" ,"0b0000_0001_0000_0010_0000_0011_0000_0100"), + ("#_n" ,"0b0000_0001_0000_0010_0000_0011_0000_0100"), + ("#_x" ,"0x0102_0304"), + ] + for (fmt, txt) in pairs: + res = format(addr, fmt) + self.assertEqual(txt, format(addr, fmt)) + def test_network_passed_as_address(self): addr = "127.0.0.1/24" @@ -271,15 +287,40 @@ def test_weakref(self): class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): factory = ipaddress.IPv6Address - def test_bits(self): - addr = "1:0db8:85a3:0000:0000:8a2e:0370:7334" - addr_obj = ipaddress.IPv6Address(addr) - self.assertEqual(addr_obj.bits, - "0b00000000000000010000110110111000" - "10000101101000110000000000000000" - "00000000000000001000101000101110" - "00000011011100000111001100110100") - + def test_format(self): + addr = ipaddress.IPv6Address("::1.2.3.4") + pairs = [ + ("b" + ,"000000000000000000000000000000000" + "000000000000000000000000000000000" + "00000000000000000000000000000000" + "000001000000100000001100000100"), + ("n" ,"00000000000000000000000001020304"), + ("x" ,"00000000000000000000000001020304"), + ("_b" + ,"0000_0000_0000_0000_0000_0000_0000_0000_" + "0000_0000_0000_0000_0000_0000_0000_0000_" + "0000_0000_0000_0000_0000_0000_0000_0000_" + "0000_0001_0000_0010_0000_0011_0000_0100"), + ("_n" ,"0000_0000_0000_0000_0000_0000_0102_0304"), + ("_x" ,"0000_0000_0000_0000_0000_0000_0102_0304"), + ("#b" + ,"0b000000000000000000000000000000000" + "000000000000000000000000000000000" + "000000000000000000000000000000000" + "00001000000100000001100000100"), + ("#n" ,"0x00000000000000000000000001020304"), + ("#x" ,"0x00000000000000000000000001020304"), + ("#_b" + ,"0b0000_0000_0000_0000_0000_0000_0000_0000_" + "0000_0000_0000_0000_0000_0000_0000_0000_" + "0000_0000_0000_0000_0000_0000_0000_0000_" + "0000_0001_0000_0010_0000_0011_0000_0100"), + ("#_n" ,"0x0000_0000_0000_0000_0000_0000_0102_0304"), + ("#_x" ,"0x0000_0000_0000_0000_0000_0000_0102_0304"), + ] + for (fmt, txt) in pairs: + res = format(addr, fmt) def test_network_passed_as_address(self): addr = "::1/24" From eddcc39bbf31a3f1dc994f5bc9a38eaf17b0b2e5 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 13 Feb 2018 12:20:56 -0500 Subject: [PATCH 09/27] updated news --- .../Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst diff --git a/Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst b/Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst new file mode 100644 index 00000000000000..3c6b258ae3b3fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst @@ -0,0 +1,10 @@ +Added __format__ to IPv4 and IPv6 classes. Always outputs a fully zero- +padded string. Supports b/h/n modifiers (bin/hex/native format). Native for +IPv4 is binary, native for IPv6 is hex. Also supporst '#' and '_' operators. +#.. section: Documentation #.. section: Tests #.. section: Build #.. +section: Windows #.. section: macOS #.. section: IDLE #.. section: +Tools/Demos #.. section: C API + +# Write your Misc/NEWS entry below. It should be a simple ReST paragraph. # +Don't start with "- Issue #: " or "- bpo-: " or that sort of stuff. +########################################################################### From eabf6d9a5f1abad555fb2227275e642ace58785c Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 13 Feb 2018 12:26:07 -0500 Subject: [PATCH 10/27] cleanup and NEWS.d --- Lib/ipaddress.py | 8 ++++---- Lib/test/test_ipaddress.py | 8 ++++---- .../next/Library/2018-02-13-12-25-43.bpo-32820.0stF0u.rst | 4 ++++ 3 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-02-13-12-25-43.bpo-32820.0stF0u.rst diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 3fef303588cb2f..e404b98d551a68 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1108,7 +1108,7 @@ def __format__(self, fmt): # resulting string is '0b' + 32 bits # plus 7 _ if needed padlen = IPV4LENGTH+2 + (7*len(separator)) - + # hex elif fmt_base == 'x': # resulting string is '0x' + 8 hex digits @@ -1120,7 +1120,7 @@ def __format__(self, fmt): # strip left two if necessary if '#' not in fmt: retstr = retstr[2:] - + else: retstr = str(self) @@ -1683,7 +1683,7 @@ def __format__(self, fmt): # resulting string is '0b' + 32 bits # plus 7 _ if needed padlen = IPV6LENGTH+2 + (31*len(separator)) - + # hex elif fmt_base == 'x': # resulting string is '0x' + 8 hex digits @@ -1695,7 +1695,7 @@ def __format__(self, fmt): # strip left two if necessary if '#' not in fmt: retstr = retstr[2:] - + else: retstr = str(self) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 8cce762230cee5..e4e06f5bea438c 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -169,10 +169,10 @@ def assertBadLength(length): class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): factory = ipaddress.IPv4Address - + def test_format(self): addr = ipaddress.IPv4Address("1.2.3.4") - pairs = [ + pairs = [ ("b" ,"00000001000000100000001100000100"), ("n" ,"00000001000000100000001100000100"), ("x" ,"01020304"), @@ -189,7 +189,7 @@ def test_format(self): for (fmt, txt) in pairs: res = format(addr, fmt) self.assertEqual(txt, format(addr, fmt)) - + def test_network_passed_as_address(self): addr = "127.0.0.1/24" @@ -289,7 +289,7 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): def test_format(self): addr = ipaddress.IPv6Address("::1.2.3.4") - pairs = [ + pairs = [ ("b" ,"000000000000000000000000000000000" "000000000000000000000000000000000" diff --git a/Misc/NEWS.d/next/Library/2018-02-13-12-25-43.bpo-32820.0stF0u.rst b/Misc/NEWS.d/next/Library/2018-02-13-12-25-43.bpo-32820.0stF0u.rst new file mode 100644 index 00000000000000..dd5bd269cbf78c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-02-13-12-25-43.bpo-32820.0stF0u.rst @@ -0,0 +1,4 @@ +Added __format__ to IPv4 and IPv6 classes. Always outputs a fully zero- +padded string. Supports b/x/n modifiers (bin/hex/native format). Native +format for IPv4 is bin, native format for IPv6 is hex. Also supports '#' and +'_' modifiers. From ba053868fe434b173673b9980bb169895d5c24ae Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 13 Feb 2018 12:28:38 -0500 Subject: [PATCH 11/27] cleaned up old NEWS --- .../Library/2018-02-11-12-41-56.bpo-32820.73532W.rst | 2 -- .../Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst | 10 ---------- 2 files changed, 12 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst delete mode 100644 Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst diff --git a/Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst b/Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst deleted file mode 100644 index 399c5225e574ad..00000000000000 --- a/Misc/NEWS.d/next/Library/2018-02-11-12-41-56.bpo-32820.73532W.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added bits() method to return the fully padded binary representation of an -IPv4 or IPv6 address. Test case included. diff --git a/Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst b/Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst deleted file mode 100644 index 3c6b258ae3b3fc..00000000000000 --- a/Misc/NEWS.d/next/Library/2018-02-13-12-20-44.bpo-32820._eGUAc.rst +++ /dev/null @@ -1,10 +0,0 @@ -Added __format__ to IPv4 and IPv6 classes. Always outputs a fully zero- -padded string. Supports b/h/n modifiers (bin/hex/native format). Native for -IPv4 is binary, native for IPv6 is hex. Also supporst '#' and '_' operators. -#.. section: Documentation #.. section: Tests #.. section: Build #.. -section: Windows #.. section: macOS #.. section: IDLE #.. section: -Tools/Demos #.. section: C API - -# Write your Misc/NEWS entry below. It should be a simple ReST paragraph. # -Don't start with "- Issue #: " or "- bpo-: " or that sort of stuff. -########################################################################### From 2bd9f601532ae86847b7f17c9142cdbf54a1d93b Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 15 Feb 2018 03:26:43 -0500 Subject: [PATCH 12/27] removed cut and paste leftover --- Lib/test/test_ipaddress.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index e4e06f5bea438c..fc2c218680788e 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -187,7 +187,6 @@ def test_format(self): ("#_x" ,"0x0102_0304"), ] for (fmt, txt) in pairs: - res = format(addr, fmt) self.assertEqual(txt, format(addr, fmt)) From d865609fa12faf921af0fe5eb50cea9a3bfbe602 Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 15 Feb 2018 03:28:56 -0500 Subject: [PATCH 13/27] one more cleanup --- Lib/test/test_ipaddress.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index fc2c218680788e..8b02d8ac86775f 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -319,7 +319,7 @@ def test_format(self): ("#_x" ,"0x0000_0000_0000_0000_0000_0000_0102_0304"), ] for (fmt, txt) in pairs: - res = format(addr, fmt) + self.assertEqual(txt, format(addr, fmt)) def test_network_passed_as_address(self): addr = "::1/24" From 798af6e96ccaa98e85aac0612269ad3cb1406721 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 4 Mar 2018 09:09:50 -0500 Subject: [PATCH 14/27] moved to regexp, moved away from v4- and v6-specific versions of __format__ --- Lib/ipaddress.py | 150 ++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index e404b98d551a68..37d4a18507cdef 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -594,6 +594,82 @@ def _get_address_key(self): def __reduce__(self): return self.__class__, (self._ip,) + def __format__(self, fmt): + """Returns a formatted string. Supported presentation types are: + 's': returns the IP address as a string (default) + 'b' or 'n': converts to binary and returns a zero-padded string + 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string + + For binary and hex presentation types, the alternate form specifier + '#' and the grouping option '_' are supported. + + """ + + import re + + ## TODO: raise the right error (ValueError?) + ## TODO: when do I call valueerror, when do I call super()? + + print("DEBUG:FMT:", fmt, len(fmt)) + + # string + if len(fmt) == 0 or fmt[-1] == 's': + # let format() handle it + return format(str(self), fmt) + + # from here on down, support for 'bnXx' + + fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') + m = fmt_re.match(fmt) + if not m: + return super().__format__(fmt) + #raise ValueError("Invalid format string") + + alternate = m.group(1) + grouping = m.group(2) + fmt_base = m.group(3) + print(f'DEBUG:alternate:{alternate}, grouping:{grouping}, fmt_base:{fmt_base}') + + # set default + if fmt_base == 'n': + if self._version == 4: + fmt_base = 'b' # binary is default for ipv4 + if self._version == 6: + fmt_base = 'x' # hex is default for ipv6 + + # binary + if fmt_base == 'b': + if self._version == 4: + # resulting string is '0b' + 32 bits + # plus 7 _ if needed + padlen = IPV4LENGTH+2 + (7*len(grouping)) + elif self._version == 6: + # resulting string is '0b' + 128 bits + # plus 31 _ if needed + padlen = IPV6LENGTH+2 + (31*len(grouping)) + + # hex + elif fmt_base in 'Xx': + if self._version == 4: + # resulting string is '0x' + 8 hex digits + # plus a single _ if needed + padlen = int(IPV4LENGTH/4)+2 + len(grouping) + elif self._version == 6: + # resulting string is '0x' + 32 hex digits + # plus 7 _ if needed + padlen = int(IPV6LENGTH/4)+2 + (7*len(grouping)) + + retstr = f'{int(self):#0{padlen}{grouping}{fmt_base}}' + if fmt_base == 'X': + retstr = retstr.upper() + + # strip left two characters if necessary + if not alternate: + retstr = retstr[2:] + + return retstr + + @functools.total_ordering class _BaseNetwork(_IPAddressBase): @@ -1089,43 +1165,6 @@ class _BaseV4: def _explode_shorthand_ip_string(self): return str(self) - def __format__(self, fmt): - """Format: ends with b for bin, h for hex, n for native (bin for ipv4, - hex for ipv6). Takes # to include 0b, and _ as a separator - """ - if len(fmt) and fmt[-1] in 'bnx': - fmt_base = fmt[-1] - if fmt_base == 'n': - fmt_base = 'b' # binary is default for ipv4 - - if '_' in fmt: - separator = '_' - else: - separator = '' - - # binary - if fmt_base == 'b': - # resulting string is '0b' + 32 bits - # plus 7 _ if needed - padlen = IPV4LENGTH+2 + (7*len(separator)) - - # hex - elif fmt_base == 'x': - # resulting string is '0x' + 8 hex digits - # plus a single _ if needed - padlen = int(IPV4LENGTH/4)+2 + len(separator) - - retstr = f'{int(self):#0{padlen}{separator}{fmt_base}}' - - # strip left two if necessary - if '#' not in fmt: - retstr = retstr[2:] - - else: - retstr = str(self) - - return retstr - @classmethod def _make_netmask(cls, arg): """Make a (netmask, prefix_len) tuple from the given argument. @@ -1664,43 +1703,6 @@ class _BaseV6: # when constructed (see _make_netmask()). _netmask_cache = {} - def __format__(self, fmt): - """Format: ends with b for bin, h for hex, n for native (bin for ipv4, - hex for ipv6). Takes # to include 0b, and _ as a separator - """ - if len(fmt) and fmt[-1] in 'bnx': - fmt_base = fmt[-1] - if fmt_base == 'n': - fmt_base = 'x' # hex is default for ipv4 - - if '_' in fmt: - separator = '_' - else: - separator = '' - - # binary - if fmt_base == 'b': - # resulting string is '0b' + 32 bits - # plus 7 _ if needed - padlen = IPV6LENGTH+2 + (31*len(separator)) - - # hex - elif fmt_base == 'x': - # resulting string is '0x' + 8 hex digits - # plus 7 single _ if needed - padlen = int(IPV6LENGTH/4)+2 + (7*len(separator)) - - retstr = f'{int(self):#0{padlen}{separator}{fmt_base}}' - - # strip left two if necessary - if '#' not in fmt: - retstr = retstr[2:] - - else: - retstr = str(self) - - return retstr - @classmethod def _make_netmask(cls, arg): """Make a (netmask, prefix_len) tuple from the given argument. From db383e17dd019b751a8e5edebeb1bd00649a4de9 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 4 Mar 2018 09:31:31 -0500 Subject: [PATCH 15/27] More cleanup, added ipv6 test cases --- Lib/ipaddress.py | 7 ++--- Lib/test/test_ipaddress.py | 63 ++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 37d4a18507cdef..37c3e31cb59478 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -610,8 +610,6 @@ def __format__(self, fmt): ## TODO: raise the right error (ValueError?) ## TODO: when do I call valueerror, when do I call super()? - print("DEBUG:FMT:", fmt, len(fmt)) - # string if len(fmt) == 0 or fmt[-1] == 's': # let format() handle it @@ -628,9 +626,8 @@ def __format__(self, fmt): alternate = m.group(1) grouping = m.group(2) fmt_base = m.group(3) - print(f'DEBUG:alternate:{alternate}, grouping:{grouping}, fmt_base:{fmt_base}') - - # set default + + # set default if fmt_base == 'n': if self._version == 4: fmt_base = 'b' # binary is default for ipv4 diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 8b02d8ac86775f..79f747d85a6c17 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -171,24 +171,55 @@ class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): factory = ipaddress.IPv4Address def test_format(self): - addr = ipaddress.IPv4Address("1.2.3.4") - pairs = [ - ("b" ,"00000001000000100000001100000100"), - ("n" ,"00000001000000100000001100000100"), - ("x" ,"01020304"), - ("_b" ,"0000_0001_0000_0010_0000_0011_0000_0100"), - ("_n" ,"0000_0001_0000_0010_0000_0011_0000_0100"), - ("_x" ,"0102_0304"), - ("#b" ,"0b00000001000000100000001100000100"), - ("#n" ,"0b00000001000000100000001100000100"), - ("#x" ,"0x01020304"), - ("#_b" ,"0b0000_0001_0000_0010_0000_0011_0000_0100"), - ("#_n" ,"0b0000_0001_0000_0010_0000_0011_0000_0100"), - ("#_x" ,"0x0102_0304"), + v4 = ipaddress.IPv4Address("1.2.3.42") + v4_pairs = [ + ("b" ,"00000001000000100000001100101010"), + ("n" ,"00000001000000100000001100101010"), + ("x" ,"0102032a"), + ("X" ,"0102032A"), + ("_b" ,"0000_0001_0000_0010_0000_0011_0010_1010"), + ("_n" ,"0000_0001_0000_0010_0000_0011_0010_1010"), + ("_x" ,"0102_032a"), + ("_X" ,"0102_032A"), + ("#b" ,"0b00000001000000100000001100101010"), + ("#n" ,"0b00000001000000100000001100101010"), + ("#x" ,"0x0102032a"), + ("#X" ,"0X0102032A"), + ("#_b" ,"0b0000_0001_0000_0010_0000_0011_0010_1010"), + ("#_n" ,"0b0000_0001_0000_0010_0000_0011_0010_1010"), + ("#_x" ,"0x0102_032a"), + ("#_X" ,"0X0102_032A"), + ] + for (fmt, txt) in v4_pairs: + self.assertEqual(txt, format(v4, fmt)) + + + v6 = ipaddress.IPv6Address("::1.2.3.42") + v6_pairs = [ + ("b", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), + ("n", "0000000000000000000000000102032a"), + ("x", "0000000000000000000000000102032a"), + ("X", "0000000000000000000000000102032A"), + ("_b", + "0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), + ("_n", "0000_0000_0000_0000_0000_0000_0102_032a"), + ("_x", "0000_0000_0000_0000_0000_0000_0102_032a"), + ("_X", "0000_0000_0000_0000_0000_0000_0102_032A"), + ("#b", + "0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), + ("#n", "0x0000000000000000000000000102032a"), + ("#x", "0x0000000000000000000000000102032a"), + ("#X", "0X0000000000000000000000000102032A"), + ("#_b", + "0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), + ("#_n", "0x0000_0000_0000_0000_0000_0000_0102_032a"), + ("#_x", "0x0000_0000_0000_0000_0000_0000_0102_032a"), + ("#_X", "0X0000_0000_0000_0000_0000_0000_0102_032A"), ] - for (fmt, txt) in pairs: - self.assertEqual(txt, format(addr, fmt)) + for (fmt, txt) in v6_pairs: + self.assertEqual(txt, format(v6, fmt)) def test_network_passed_as_address(self): addr = "127.0.0.1/24" From b4332820d35bd394d549d9a708b1a83e256b622d Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 4 Mar 2018 09:35:27 -0500 Subject: [PATCH 16/27] more cleanup --- Lib/ipaddress.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 37c3e31cb59478..1e9bb8ff4ac185 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -607,9 +607,6 @@ def __format__(self, fmt): import re - ## TODO: raise the right error (ValueError?) - ## TODO: when do I call valueerror, when do I call super()? - # string if len(fmt) == 0 or fmt[-1] == 's': # let format() handle it @@ -621,7 +618,6 @@ def __format__(self, fmt): m = fmt_re.match(fmt) if not m: return super().__format__(fmt) - #raise ValueError("Invalid format string") alternate = m.group(1) grouping = m.group(2) @@ -657,6 +653,7 @@ def __format__(self, fmt): padlen = int(IPV6LENGTH/4)+2 + (7*len(grouping)) retstr = f'{int(self):#0{padlen}{grouping}{fmt_base}}' + if fmt_base == 'X': retstr = retstr.upper() From 41109cca5921cb9a13578149ab324e149f12c911 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 4 Mar 2018 09:52:06 -0500 Subject: [PATCH 17/27] more cleanup --- Lib/ipaddress.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 1e9bb8ff4ac185..86e155a12a728a 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -597,8 +597,8 @@ def __reduce__(self): def __format__(self, fmt): """Returns a formatted string. Supported presentation types are: 's': returns the IP address as a string (default) - 'b' or 'n': converts to binary and returns a zero-padded string - 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string + 'b' or 'n': converts to binary and returns a zero-padded string + 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string For binary and hex presentation types, the alternate form specifier '#' and the grouping option '_' are supported. @@ -606,15 +606,16 @@ def __format__(self, fmt): """ import re - + fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') + # string if len(fmt) == 0 or fmt[-1] == 's': # let format() handle it return format(str(self), fmt) # from here on down, support for 'bnXx' - - fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') + + #fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') m = fmt_re.match(fmt) if not m: return super().__format__(fmt) @@ -622,7 +623,7 @@ def __format__(self, fmt): alternate = m.group(1) grouping = m.group(2) fmt_base = m.group(3) - + # set default if fmt_base == 'n': if self._version == 4: From 861b5e47677998708c5d987b1974a8bed06363e0 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 4 Mar 2018 10:24:27 -0500 Subject: [PATCH 18/27] cleanup --- Lib/ipaddress.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 86e155a12a728a..b19d029c040a96 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -605,8 +605,6 @@ def __format__(self, fmt): """ - import re - fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') # string if len(fmt) == 0 or fmt[-1] == 's': @@ -615,7 +613,8 @@ def __format__(self, fmt): # from here on down, support for 'bnXx' - #fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') + import re + fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') m = fmt_re.match(fmt) if not m: return super().__format__(fmt) From 398b2c753432bfb38ee7d4b84b1d8dc715b46e7b Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 4 Mar 2018 19:14:05 -0500 Subject: [PATCH 19/27] cleanup --- Lib/test/test_ipaddress.py | 86 ++++++++++++-------------------------- 1 file changed, 26 insertions(+), 60 deletions(-) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 79f747d85a6c17..cae1dd85be2cd5 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -193,34 +193,6 @@ def test_format(self): for (fmt, txt) in v4_pairs: self.assertEqual(txt, format(v4, fmt)) - - v6 = ipaddress.IPv6Address("::1.2.3.42") - v6_pairs = [ - ("b", - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), - ("n", "0000000000000000000000000102032a"), - ("x", "0000000000000000000000000102032a"), - ("X", "0000000000000000000000000102032A"), - ("_b", - "0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), - ("_n", "0000_0000_0000_0000_0000_0000_0102_032a"), - ("_x", "0000_0000_0000_0000_0000_0000_0102_032a"), - ("_X", "0000_0000_0000_0000_0000_0000_0102_032A"), - ("#b", - "0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), - ("#n", "0x0000000000000000000000000102032a"), - ("#x", "0x0000000000000000000000000102032a"), - ("#X", "0X0000000000000000000000000102032A"), - ("#_b", - "0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), - ("#_n", "0x0000_0000_0000_0000_0000_0000_0102_032a"), - ("#_x", "0x0000_0000_0000_0000_0000_0000_0102_032a"), - ("#_X", "0X0000_0000_0000_0000_0000_0000_0102_032A"), - ] - - for (fmt, txt) in v6_pairs: - self.assertEqual(txt, format(v6, fmt)) - def test_network_passed_as_address(self): addr = "127.0.0.1/24" with self.assertAddressError("Unexpected '/' in %r", addr): @@ -318,39 +290,33 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): factory = ipaddress.IPv6Address def test_format(self): - addr = ipaddress.IPv6Address("::1.2.3.4") - pairs = [ - ("b" - ,"000000000000000000000000000000000" - "000000000000000000000000000000000" - "00000000000000000000000000000000" - "000001000000100000001100000100"), - ("n" ,"00000000000000000000000001020304"), - ("x" ,"00000000000000000000000001020304"), - ("_b" - ,"0000_0000_0000_0000_0000_0000_0000_0000_" - "0000_0000_0000_0000_0000_0000_0000_0000_" - "0000_0000_0000_0000_0000_0000_0000_0000_" - "0000_0001_0000_0010_0000_0011_0000_0100"), - ("_n" ,"0000_0000_0000_0000_0000_0000_0102_0304"), - ("_x" ,"0000_0000_0000_0000_0000_0000_0102_0304"), - ("#b" - ,"0b000000000000000000000000000000000" - "000000000000000000000000000000000" - "000000000000000000000000000000000" - "00001000000100000001100000100"), - ("#n" ,"0x00000000000000000000000001020304"), - ("#x" ,"0x00000000000000000000000001020304"), - ("#_b" - ,"0b0000_0000_0000_0000_0000_0000_0000_0000_" - "0000_0000_0000_0000_0000_0000_0000_0000_" - "0000_0000_0000_0000_0000_0000_0000_0000_" - "0000_0001_0000_0010_0000_0011_0000_0100"), - ("#_n" ,"0x0000_0000_0000_0000_0000_0000_0102_0304"), - ("#_x" ,"0x0000_0000_0000_0000_0000_0000_0102_0304"), + + v6 = ipaddress.IPv6Address("::1.2.3.42") + v6_pairs = [ + ("b", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), + ("n", "0000000000000000000000000102032a"), + ("x", "0000000000000000000000000102032a"), + ("X", "0000000000000000000000000102032A"), + ("_b", + "0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), + ("_n", "0000_0000_0000_0000_0000_0000_0102_032a"), + ("_x", "0000_0000_0000_0000_0000_0000_0102_032a"), + ("_X", "0000_0000_0000_0000_0000_0000_0102_032A"), + ("#b", + "0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), + ("#n", "0x0000000000000000000000000102032a"), + ("#x", "0x0000000000000000000000000102032a"), + ("#X", "0X0000000000000000000000000102032A"), + ("#_b", + "0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), + ("#_n", "0x0000_0000_0000_0000_0000_0000_0102_032a"), + ("#_x", "0x0000_0000_0000_0000_0000_0000_0102_032a"), + ("#_X", "0X0000_0000_0000_0000_0000_0000_0102_032A"), ] - for (fmt, txt) in pairs: - self.assertEqual(txt, format(addr, fmt)) + + for (fmt, txt) in v6_pairs: + self.assertEqual(txt, format(v6, fmt)) def test_network_passed_as_address(self): addr = "::1/24" From 0274c0f2f0504e64dd7810bfbe8130f9d9616ca5 Mon Sep 17 00:00:00 2001 From: Eric Osborne Date: Wed, 12 Sep 2018 10:08:52 -0400 Subject: [PATCH 20/27] cleanup per review, part 1 --- Lib/ipaddress.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index b19d029c040a96..a2ebec189300ac 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -606,12 +606,12 @@ def __format__(self, fmt): """ - # string - if len(fmt) == 0 or fmt[-1] == 's': + # Support string formatting + if not fmt or fmt[-1] == 's': # let format() handle it return format(str(self), fmt) - # from here on down, support for 'bnXx' + # From here on down, support for 'bnXx' import re fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') @@ -623,14 +623,14 @@ def __format__(self, fmt): grouping = m.group(2) fmt_base = m.group(3) - # set default + # Set some defaults if fmt_base == 'n': if self._version == 4: - fmt_base = 'b' # binary is default for ipv4 + fmt_base = 'b' # Binary is default for ipv4 if self._version == 6: - fmt_base = 'x' # hex is default for ipv6 + fmt_base = 'x' # Hex is default for ipv6 - # binary + # Handle binary formatting if fmt_base == 'b': if self._version == 4: # resulting string is '0b' + 32 bits @@ -641,7 +641,7 @@ def __format__(self, fmt): # plus 31 _ if needed padlen = IPV6LENGTH+2 + (31*len(grouping)) - # hex + # Handle hex formatting elif fmt_base in 'Xx': if self._version == 4: # resulting string is '0x' + 8 hex digits @@ -657,7 +657,8 @@ def __format__(self, fmt): if fmt_base == 'X': retstr = retstr.upper() - # strip left two characters if necessary + # If alternate is not set, strip the two leftmost + # characters ('0b') if not alternate: retstr = retstr[2:] From 6d5fbdb3346e4ae1751ac9a03936f00dd91e70e3 Mon Sep 17 00:00:00 2001 From: Eric Osborne Date: Wed, 12 Sep 2018 15:51:18 -0400 Subject: [PATCH 21/27] addressed review comments around help string and regexp matching --- Lib/ipaddress.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index a2ebec189300ac..9eaf44093ec733 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -595,7 +595,9 @@ def __reduce__(self): return self.__class__, (self._ip,) def __format__(self, fmt): - """Returns a formatted string. Supported presentation types are: + """Returns an IP address as a formatted string. + + Supported presentation types are: 's': returns the IP address as a string (default) 'b' or 'n': converts to binary and returns a zero-padded string 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string @@ -614,14 +616,15 @@ def __format__(self, fmt): # From here on down, support for 'bnXx' import re - fmt_re = re.compile('^(#?)(_?)(x|b|n|X){1}$') - m = fmt_re.match(fmt) + fmt_re = '^(?P#?)(?P_?)(?P[xbnX]){1}$' + m = re.match(fmt_re, fmt) if not m: return super().__format__(fmt) - alternate = m.group(1) - grouping = m.group(2) - fmt_base = m.group(3) + groupdict = m.groupdict() + alternate = groupdict['alternate'] + grouping = groupdict['grouping'] + fmt_base = groupdict['fmt_base'] # Set some defaults if fmt_base == 'n': From d9061d2ae7ebe9b092b4b44eef51e0dae39a6620 Mon Sep 17 00:00:00 2001 From: Eric Osborne Date: Thu, 13 Sep 2018 05:39:20 -0400 Subject: [PATCH 22/27] wrapped v6 test strings. contiguous integers: break at 72char. with underscores: break so that it looks clean. --- Lib/test/test_ipaddress.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index cae1dd85be2cd5..3af29b34bf0e04 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -293,23 +293,33 @@ def test_format(self): v6 = ipaddress.IPv6Address("::1.2.3.42") v6_pairs = [ - ("b", - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), + ("b", + "000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000010000" + "00100000001100101010"), ("n", "0000000000000000000000000102032a"), ("x", "0000000000000000000000000102032a"), ("X", "0000000000000000000000000102032A"), ("_b", - "0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), + "0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000" + "_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000" + "_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010" + "_1010"), ("_n", "0000_0000_0000_0000_0000_0000_0102_032a"), ("_x", "0000_0000_0000_0000_0000_0000_0102_032a"), ("_X", "0000_0000_0000_0000_0000_0000_0102_032A"), ("#b", - "0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000001100101010"), + "0b0000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000100" + "0000100000001100101010"), ("#n", "0x0000000000000000000000000102032a"), ("#x", "0x0000000000000000000000000102032a"), ("#X", "0X0000000000000000000000000102032A"), ("#_b", - "0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011_0010_1010"), + "0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000" + "_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000" + "_0000_0000_0000_0000_0000_0001_0000_0010_0000_0011" + "_0010_1010"), ("#_n", "0x0000_0000_0000_0000_0000_0000_0102_032a"), ("#_x", "0x0000_0000_0000_0000_0000_0000_0102_032a"), ("#_X", "0X0000_0000_0000_0000_0000_0000_0102_032A"), From 140114203b1b766246c45c5d733bf1dd5a3fe544 Mon Sep 17 00:00:00 2001 From: Eric Osborne Date: Thu, 13 Sep 2018 07:36:06 -0400 Subject: [PATCH 23/27] 's' and '' tests for pv4 and ipv6 --- Lib/test/test_ipaddress.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 3af29b34bf0e04..f2b6bdae0bf46f 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -189,6 +189,8 @@ def test_format(self): ("#_n" ,"0b0000_0001_0000_0010_0000_0011_0010_1010"), ("#_x" ,"0x0102_032a"), ("#_X" ,"0X0102_032A"), + ("s" ,"1.2.3.42"), + ("" ,"1.2.3.42"), ] for (fmt, txt) in v4_pairs: self.assertEqual(txt, format(v4, fmt)) @@ -323,6 +325,8 @@ def test_format(self): ("#_n", "0x0000_0000_0000_0000_0000_0000_0102_032a"), ("#_x", "0x0000_0000_0000_0000_0000_0000_0102_032a"), ("#_X", "0X0000_0000_0000_0000_0000_0000_0102_032A"), + ("s", "::102:32a"), + ("", "::102:32a"), ] for (fmt, txt) in v6_pairs: From acc1f06d24ee5a98d1fc5edb828928fcaa4c1330 Mon Sep 17 00:00:00 2001 From: Eric Osborne Date: Sat, 15 Sep 2018 17:56:14 -0400 Subject: [PATCH 24/27] whitespace cleanup --- Lib/ipaddress.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 9eaf44093ec733..6186cdc45bd640 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -597,14 +597,13 @@ def __reduce__(self): def __format__(self, fmt): """Returns an IP address as a formatted string. - Supported presentation types are: - 's': returns the IP address as a string (default) - 'b' or 'n': converts to binary and returns a zero-padded string - 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string - - For binary and hex presentation types, the alternate form specifier - '#' and the grouping option '_' are supported. + Supported presentation types are: + 's': returns the IP address as a string (default) + 'b' or 'n': converts to binary and returns a zero-padded string + 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string + For binary and hex presentation types, the alternate form specifier + '#' and the grouping option '_' are supported. """ From 83547568b63cf46765072f66b86c0d2a7517ab84 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Mon, 9 Sep 2019 23:02:40 +0100 Subject: [PATCH 25/27] Remove trailing whitespace --- Lib/ipaddress.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 6186cdc45bd640..0cd52ae77a2918 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -595,8 +595,8 @@ def __reduce__(self): return self.__class__, (self._ip,) def __format__(self, fmt): - """Returns an IP address as a formatted string. - + """Returns an IP address as a formatted string. + Supported presentation types are: 's': returns the IP address as a string (default) 'b' or 'n': converts to binary and returns a zero-padded string From aaaa45ce64019424382b162def8f96a204754b51 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Wed, 11 Sep 2019 18:34:37 +0100 Subject: [PATCH 26/27] Remove more trailing whitespace --- Lib/ipaddress.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 0cd52ae77a2918..31ce57b23b86ff 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -632,7 +632,7 @@ def __format__(self, fmt): if self._version == 6: fmt_base = 'x' # Hex is default for ipv6 - # Handle binary formatting + # Handle binary formatting if fmt_base == 'b': if self._version == 4: # resulting string is '0b' + 32 bits From 8e1d9ca4ace0349518ac31c45c204733a6cc39b4 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Wed, 11 Sep 2019 19:09:37 +0100 Subject: [PATCH 27/27] Remove an excess blank line --- Lib/ipaddress.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 31ce57b23b86ff..ef4fe21e435cc7 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -667,7 +667,6 @@ def __format__(self, fmt): return retstr - @functools.total_ordering class _BaseNetwork(_IPAddressBase):