summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_format.py
diff options
context:
space:
mode:
authorJohn Belmonte <john@neggie.net>2022-04-11 14:34:18 (GMT)
committerGitHub <noreply@github.com>2022-04-11 14:34:18 (GMT)
commitb0b836b20cb56c225874a4a39ef895f89ab2970f (patch)
treeb333cd2e9ee95021e1fc3b45eee2da0b7ac0ee35 /Lib/test/test_format.py
parentdd207a6ac52d4bd9a71cf178fc1d5c17a6f07aff (diff)
downloadcpython-b0b836b20cb56c225874a4a39ef895f89ab2970f.zip
cpython-b0b836b20cb56c225874a4a39ef895f89ab2970f.tar.gz
cpython-b0b836b20cb56c225874a4a39ef895f89ab2970f.tar.bz2
bpo-45995: add "z" format specifer to coerce negative 0 to zero (GH-30049)
Add "z" format specifier to coerce negative 0 to zero. See https://github.com/python/cpython/issues/90153 (originally https://bugs.python.org/issue45995) for discussion. This covers `str.format()` and f-strings. Old-style string interpolation is not supported. Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
Diffstat (limited to 'Lib/test/test_format.py')
-rw-r--r--Lib/test/test_format.py74
1 files changed, 74 insertions, 0 deletions
diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
index 16d29d1..69b0d5f 100644
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -546,6 +546,80 @@ class FormatTest(unittest.TestCase):
with self.assertRaisesRegex(ValueError, str_err):
"{a:%ЫйЯЧ}".format(a='a')
+ def test_negative_zero(self):
+ ## default behavior
+ self.assertEqual(f"{-0.:.1f}", "-0.0")
+ self.assertEqual(f"{-.01:.1f}", "-0.0")
+ self.assertEqual(f"{-0:.1f}", "0.0") # integers do not distinguish -0
+
+ ## z sign option
+ self.assertEqual(f"{0.:z.1f}", "0.0")
+ self.assertEqual(f"{0.:z6.1f}", " 0.0")
+ self.assertEqual(f"{-1.:z6.1f}", " -1.0")
+ self.assertEqual(f"{-0.:z.1f}", "0.0")
+ self.assertEqual(f"{.01:z.1f}", "0.0")
+ self.assertEqual(f"{-0:z.1f}", "0.0") # z is allowed for integer input
+ self.assertEqual(f"{-.01:z.1f}", "0.0")
+ self.assertEqual(f"{0.:z.2f}", "0.00")
+ self.assertEqual(f"{-0.:z.2f}", "0.00")
+ self.assertEqual(f"{.001:z.2f}", "0.00")
+ self.assertEqual(f"{-.001:z.2f}", "0.00")
+
+ self.assertEqual(f"{0.:z.1e}", "0.0e+00")
+ self.assertEqual(f"{-0.:z.1e}", "0.0e+00")
+ self.assertEqual(f"{0.:z.1E}", "0.0E+00")
+ self.assertEqual(f"{-0.:z.1E}", "0.0E+00")
+
+ self.assertEqual(f"{-0.001:z.2e}", "-1.00e-03") # tests for mishandled
+ # rounding
+ self.assertEqual(f"{-0.001:z.2g}", "-0.001")
+ self.assertEqual(f"{-0.001:z.2%}", "-0.10%")
+
+ self.assertEqual(f"{-00000.000001:z.1f}", "0.0")
+ self.assertEqual(f"{-00000.:z.1f}", "0.0")
+ self.assertEqual(f"{-.0000000000:z.1f}", "0.0")
+
+ self.assertEqual(f"{-00000.000001:z.2f}", "0.00")
+ self.assertEqual(f"{-00000.:z.2f}", "0.00")
+ self.assertEqual(f"{-.0000000000:z.2f}", "0.00")
+
+ self.assertEqual(f"{.09:z.1f}", "0.1")
+ self.assertEqual(f"{-.09:z.1f}", "-0.1")
+
+ self.assertEqual(f"{-0.: z.0f}", " 0")
+ self.assertEqual(f"{-0.:+z.0f}", "+0")
+ self.assertEqual(f"{-0.:-z.0f}", "0")
+ self.assertEqual(f"{-1.: z.0f}", "-1")
+ self.assertEqual(f"{-1.:+z.0f}", "-1")
+ self.assertEqual(f"{-1.:-z.0f}", "-1")
+
+ self.assertEqual(f"{0.j:z.1f}", "0.0+0.0j")
+ self.assertEqual(f"{-0.j:z.1f}", "0.0+0.0j")
+ self.assertEqual(f"{.01j:z.1f}", "0.0+0.0j")
+ self.assertEqual(f"{-.01j:z.1f}", "0.0+0.0j")
+
+ self.assertEqual(f"{-0.:z>6.1f}", "zz-0.0") # test fill, esp. 'z' fill
+ self.assertEqual(f"{-0.:z>z6.1f}", "zzz0.0")
+ self.assertEqual(f"{-0.:x>z6.1f}", "xxx0.0")
+ self.assertEqual(f"{-0.:🖤>z6.1f}", "🖤🖤🖤0.0") # multi-byte fill char
+
+ def test_specifier_z_error(self):
+ error_msg = re.compile("Invalid format specifier '.*z.*'")
+ with self.assertRaisesRegex(ValueError, error_msg):
+ f"{0:z+f}" # wrong position
+ with self.assertRaisesRegex(ValueError, error_msg):
+ f"{0:fz}" # wrong position
+
+ error_msg = re.escape("Negative zero coercion (z) not allowed")
+ with self.assertRaisesRegex(ValueError, error_msg):
+ f"{0:zd}" # can't apply to int presentation type
+ with self.assertRaisesRegex(ValueError, error_msg):
+ f"{'x':zs}" # can't apply to string
+
+ error_msg = re.escape("unsupported format character 'z'")
+ with self.assertRaisesRegex(ValueError, error_msg):
+ "%z.1f" % 0 # not allowed in old style string interpolation
+
if __name__ == "__main__":
unittest.main()