|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +# There are tests here with unicode string literals and |
| 3 | +# identifiers. There's a code in ast.c that was added because of a |
| 4 | +# failure with a non-ascii-only expression. So, I have tests for |
| 5 | +# that. There are workarounds that would let me run tests for that |
| 6 | +# code without unicode identifiers and strings, but just using them |
| 7 | +# directly seems like the easiest and therefore safest thing to do. |
| 8 | +# Unicode identifiers in tests is allowed by PEP 3131. |
| 9 | + |
1 | 10 | import ast
|
2 | 11 | import types
|
3 | 12 | import decimal
|
@@ -878,6 +887,12 @@ def test_not_equal(self):
|
878 | 887 | self.assertEqual(f'{3!=4!s}', 'True')
|
879 | 888 | self.assertEqual(f'{3!=4!s:.3}', 'Tru')
|
880 | 889 |
|
| 890 | + def test_equal_equal(self): |
| 891 | + # Because an expression ending in = has special meaning, |
| 892 | + # there's a special test for ==. Make sure it works. |
| 893 | + |
| 894 | + self.assertEqual(f'{0==1}', 'False') |
| 895 | + |
881 | 896 | def test_conversions(self):
|
882 | 897 | self.assertEqual(f'{3.14:10.10}', ' 3.14')
|
883 | 898 | self.assertEqual(f'{3.14!s:10.10}', '3.14 ')
|
@@ -1049,6 +1064,100 @@ def test_backslash_char(self):
|
1049 | 1064 | self.assertEqual(eval('f"\\\n"'), '')
|
1050 | 1065 | self.assertEqual(eval('f"\\\r"'), '')
|
1051 | 1066 |
|
| 1067 | + def test_debug_conversion(self): |
| 1068 | + x = 'A string' |
| 1069 | + self.assertEqual(f'{x=}', 'x=' + repr(x)) |
| 1070 | + self.assertEqual(f'{x =}', 'x =' + repr(x)) |
| 1071 | + self.assertEqual(f'{x=!s}', 'x=' + str(x)) |
| 1072 | + self.assertEqual(f'{x=!r}', 'x=' + repr(x)) |
| 1073 | + self.assertEqual(f'{x=!a}', 'x=' + ascii(x)) |
| 1074 | + |
| 1075 | + x = 2.71828 |
| 1076 | + self.assertEqual(f'{x=:.2f}', 'x=' + format(x, '.2f')) |
| 1077 | + self.assertEqual(f'{x=:}', 'x=' + format(x, '')) |
| 1078 | + self.assertEqual(f'{x=!r:^20}', 'x=' + format(repr(x), '^20')) |
| 1079 | + self.assertEqual(f'{x=!s:^20}', 'x=' + format(str(x), '^20')) |
| 1080 | + self.assertEqual(f'{x=!a:^20}', 'x=' + format(ascii(x), '^20')) |
| 1081 | + |
| 1082 | + x = 9 |
| 1083 | + self.assertEqual(f'{3*x+15=}', '3*x+15=42') |
| 1084 | + |
| 1085 | + # There is code in ast.c that deals with non-ascii expression values. So, |
| 1086 | + # use a unicode identifier to trigger that. |
| 1087 | + tenπ = 31.4 |
| 1088 | + self.assertEqual(f'{tenπ=:.2f}', 'tenπ=31.40') |
| 1089 | + |
| 1090 | + # Also test with Unicode in non-identifiers. |
| 1091 | + self.assertEqual(f'{"Σ"=}', '"Σ"=\'Σ\'') |
| 1092 | + |
| 1093 | + # Make sure nested fstrings still work. |
| 1094 | + self.assertEqual(f'{f"{3.1415=:.1f}":*^20}', '*****3.1415=3.1*****') |
| 1095 | + |
| 1096 | + # Make sure text before and after an expression with = works |
| 1097 | + # correctly. |
| 1098 | + pi = 'π' |
| 1099 | + self.assertEqual(f'alpha α {pi=} ω omega', "alpha α pi='π' ω omega") |
| 1100 | + |
| 1101 | + # Check multi-line expressions. |
| 1102 | + self.assertEqual(f'''{ |
| 1103 | +3 |
| 1104 | +=}''', '\n3\n=3') |
| 1105 | + |
| 1106 | + # Since = is handled specially, make sure all existing uses of |
| 1107 | + # it still work. |
| 1108 | + |
| 1109 | + self.assertEqual(f'{0==1}', 'False') |
| 1110 | + self.assertEqual(f'{0!=1}', 'True') |
| 1111 | + self.assertEqual(f'{0<=1}', 'True') |
| 1112 | + self.assertEqual(f'{0>=1}', 'False') |
| 1113 | + self.assertEqual(f'{(x:="5")}', '5') |
| 1114 | + self.assertEqual(x, '5') |
| 1115 | + self.assertEqual(f'{(x:=5)}', '5') |
| 1116 | + self.assertEqual(x, 5) |
| 1117 | + self.assertEqual(f'{"="}', '=') |
| 1118 | + |
| 1119 | + x = 20 |
| 1120 | + # This isn't an assignment expression, it's 'x', with a format |
| 1121 | + # spec of '=10'. See test_walrus: you need to use parens. |
| 1122 | + self.assertEqual(f'{x:=10}', ' 20') |
| 1123 | + |
| 1124 | + # Test named function parameters, to make sure '=' parsing works |
| 1125 | + # there. |
| 1126 | + def f(a): |
| 1127 | + nonlocal x |
| 1128 | + oldx = x |
| 1129 | + x = a |
| 1130 | + return oldx |
| 1131 | + x = 0 |
| 1132 | + self.assertEqual(f'{f(a="3=")}', '0') |
| 1133 | + self.assertEqual(x, '3=') |
| 1134 | + self.assertEqual(f'{f(a=4)}', '3=') |
| 1135 | + self.assertEqual(x, 4) |
| 1136 | + |
| 1137 | + # Make sure __format__ is being called. |
| 1138 | + class C: |
| 1139 | + def __format__(self, s): |
| 1140 | + return f'FORMAT-{s}' |
| 1141 | + def __repr__(self): |
| 1142 | + return 'REPR' |
| 1143 | + |
| 1144 | + self.assertEqual(f'{C()=}', 'C()=REPR') |
| 1145 | + self.assertEqual(f'{C()=!r}', 'C()=REPR') |
| 1146 | + self.assertEqual(f'{C()=:}', 'C()=FORMAT-') |
| 1147 | + self.assertEqual(f'{C()=: }', 'C()=FORMAT- ') |
| 1148 | + self.assertEqual(f'{C()=:x}', 'C()=FORMAT-x') |
| 1149 | + self.assertEqual(f'{C()=!r:*^20}', 'C()=********REPR********') |
| 1150 | + |
| 1151 | + def test_walrus(self): |
| 1152 | + x = 20 |
| 1153 | + # This isn't an assignment expression, it's 'x', with a format |
| 1154 | + # spec of '=10'. |
| 1155 | + self.assertEqual(f'{x:=10}', ' 20') |
| 1156 | + |
| 1157 | + # This is an assignment expression, which requires parens. |
| 1158 | + self.assertEqual(f'{(x:=10)}', '10') |
| 1159 | + self.assertEqual(x, 10) |
| 1160 | + |
1052 | 1161 |
|
1053 | 1162 | if __name__ == '__main__':
|
1054 | 1163 | unittest.main()
|
0 commit comments