Skip to content

Commit 4c7453f

Browse files
committed
[GR-25214] More formatting fixes.
PullRequest: graalpython/1171
2 parents 370b1af + 5d80031 commit 4c7453f

File tree

11 files changed

+78
-136
lines changed

11 files changed

+78
-136
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_formatting.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ def test_complex_formatting():
114114
assert format(complex(1, float("Inf")), "") == "(1+infj)"
115115
assert format(MyComplex(3j), "") == "42"
116116
assert format(MyComplex(3j), " <5") == "3j "
117+
assert format(complex(2**53 + 1, 0)) == '(9007199254740992+0j)'
117118

118119

119120
class AnyRepr:

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_complex.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_conjugate
44
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_divmod
55
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_file
6+
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_format
67
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_getnewargs
78
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_neg
89
*graalpython.lib-python.3.test.test_complex.ComplexTest.test_negated_imaginary_literal

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_float.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
*graalpython.lib-python.3.test.test_float.ReprTestCase.test_repr
3636
*graalpython.lib-python.3.test.test_float.ReprTestCase.test_short_repr
3737
*graalpython.lib-python.3.test.test_float.RoundTestCase.test_None_ndigits
38+
*graalpython.lib-python.3.test.test_float.RoundTestCase.test_format_specials
3839
*graalpython.lib-python.3.test.test_float.RoundTestCase.test_inf_nan
3940
*graalpython.lib-python.3.test.test_float.RoundTestCase.test_large_n
4041
*graalpython.lib-python.3.test.test_float.RoundTestCase.test_matches_float_format

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,11 +714,11 @@ PNotImplemented doGeneric(Object left, Object right) {
714714
@Builtin(name = __REPR__, minNumOfPositionalArgs = 1)
715715
abstract static class ReprNode extends PythonUnaryBuiltinNode {
716716
@Specialization
717-
@TruffleBoundary
718717
String repr(PComplex self) {
719718
return repr(self, getCore());
720719
}
721720

721+
@TruffleBoundary
722722
private static String repr(PComplex self, PythonCore core) {
723723
ComplexFormatter formatter = new ComplexFormatter(core, new Spec(-1, Spec.NONE));
724724
formatter.format(self);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,8 +2630,12 @@ private static void validateIntegerSpec(PythonCore core, Spec spec) {
26302630
if (Spec.specified(spec.precision)) {
26312631
throw core.raise(ValueError, ErrorMessages.PRECISION_NOT_ALLOWED_FOR_INT);
26322632
}
2633-
if (spec.type == 'c' && Spec.specified(spec.sign)) {
2634-
throw core.raise(ValueError, ErrorMessages.SIGN_NOT_ALLOWED_WITH_C_FOR_INT);
2633+
if (spec.type == 'c') {
2634+
if (Spec.specified(spec.sign)) {
2635+
throw core.raise(ValueError, ErrorMessages.SIGN_NOT_ALLOWED_WITH_C_FOR_INT);
2636+
} else if (spec.alternate) {
2637+
throw core.raise(ValueError, ErrorMessages.ALTERNATE_NOT_ALLOWED_WITH_C_FOR_INT);
2638+
}
26352639
}
26362640
}
26372641
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,30 @@ Object emptyFormat(VirtualFrame frame, Object self, @SuppressWarnings("unused")
180180
Object format(Object self, String formatString,
181181
@Cached CastToJavaStringCheckedNode castToJavaStringNode) {
182182
String str = castToJavaStringNode.cast(self, INVALID_RECEIVER, __STR__, self);
183-
return formatString(getCore(), formatString, str);
183+
return formatString(getCore(), getAndValidateSpec(formatString), str);
184184
}
185185

186186
@Fallback
187187
Object other(@SuppressWarnings("unused") Object self, Object formatString) {
188188
throw raise(PythonBuiltinClassType.TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", formatString);
189189
}
190190

191+
private Spec getAndValidateSpec(String formatString) {
192+
Spec spec = InternalFormat.fromText(getCore(), formatString, __FORMAT__);
193+
if (Spec.specified(spec.type) && spec.type != 's') {
194+
throw raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNKNOWN_FORMAT_CODE, spec.type, "str");
195+
}
196+
if (spec.alternate) {
197+
throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.ALTERNATE_NOT_ALLOWED_WITH_STRING_FMT);
198+
}
199+
if (Spec.specified(spec.align) && spec.align == '=') {
200+
throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.EQUALS_ALIGNMENT_FLAG_NOT_ALLOWED_FOR_STRING_FMT);
201+
}
202+
return spec;
203+
}
204+
191205
@TruffleBoundary
192-
private static Object formatString(PythonCore core, String formatString, String str) {
193-
Spec spec = InternalFormat.fromText(core, formatString, __FORMAT__);
206+
private static Object formatString(PythonCore core, Spec spec, String str) {
194207
TextFormatter formatter = new TextFormatter(core, spec.withDefaults(Spec.STRING));
195208
formatter.format(str);
196209
return formatter.pad().getResult();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,10 @@ public abstract class ErrorMessages {
104104
public static final String CAN_ONLY_CONCAT_S_NOT_P_TO_S = "can only concatenate %s (not \"%p\") to %s";
105105
public static final String CAN_ONLY_JOIN_ITERABLE = "can only join an iterable";
106106
public static final String CANNOT_ASSIGN_TO = "cannot assign to %s";
107-
public static final String CANNOT_BE_INTEPRETED_AS_INT = "%s cannot be interpreted as int (type %p)";
108107
public static final String CANNOT_BE_INTEPRETED_AS_LONG = "%s cannot be interpreted as long (type %p)";
109108
public static final String CANNOT_BE_NEGATIVE = "%s cannot be negative";
110109
public static final String CANNOT_CALL_CTOR_OF = "cannot call constructor of %s";
111110
public static final String CANNOT_CLOSE_EXPORTED_PTRS_EXIST = "cannot close exported pointers exist";
112-
public static final String CANNOT_CONERT_DICT_UPDATE_SEQ = "cannot convert dictionary update sequence element #%d to a sequence";
113111
public static final String CANNOT_CONVERT_DICT_UPDATE_SEQ = "cannot convert dictionary update sequence element #%d to a sequence";
114112
public static final String CANNOT_CONVERT_FLOAT_F_TO_INT = "cannot convert float %f to integer";
115113
public static final String CANNOT_CONVERT_OBJ_TO_C_STRING = "Cannot convert object of type %p to C string.";
@@ -139,7 +137,6 @@ public abstract class ErrorMessages {
139137
public static final String CANNOT_SPECIFY_MEM_LIMIT = "Cannot specify memory limit with FORMAT_RAW";
140138
public static final String CANNOT_SPECIFY_PREST_AND_FILTER_CHAIN = "Cannot specify both preset and filter chain";
141139
public static final String CANNOT_USE_TO_INITIALIZE_ARRAY = "cannot use a %p to initialize an array with typecode '%s'";
142-
public static final String CANT_APPLY_THIS_S_TO_P_OBJECT = "can't apply this %s to %p object";
143140
public static final String CANT_CONCAT_S_TO_P = "can't concat %s to %p";
144141
public static final String CANT_CONVERT_TO_FLOAT = "can't convert %s to float";
145142
public static final String CANT_CONVERT_TO_STR_EXPLICITELY = "Can't convert '%p' object to str implicitly";
@@ -181,7 +178,6 @@ public abstract class ErrorMessages {
181178
public static final String DESC_S_FOR_S_DOESNT_APPLY_TO_S = "descriptor '%s' for '%s' objects doesn't apply to '%s' object";
182179
public static final String DESCRIPTOR_REQUIRES_OBJ = "descriptor '%s' requires a '%s' object but received a '%p'";
183180
public static final String DICT_CHANGED_DURING_COMPARISON = "dictionary changed during comparison operation";
184-
public static final String DICT_KEYS_CHANGED_DURING_ITERATION = "dictionary keys changed during iteration";
185181
public static final String CHANGED_SIZE_DURING_ITERATION = "%s changed size during iteration";
186182
public static final String DICT_MUST_BE_SET_TO_DICT = "__dict__ must have been set to a dictionary, not a '%p'";
187183
public static final String DICT_OF_P_OBJECTS_HAS_NO_ATTR = "'%p' dict of '%p' object has no attribute '__setitem__'";
@@ -237,7 +233,6 @@ public abstract class ErrorMessages {
237233
public static final String GENERATOR_ALREADY_EXECUTING = "generator already executing";
238234
public static final String GETTING_THER_SOURCE_NOT_SUPPORTED_FOR_P = "getting the source is not supported for '%p'";
239235
public static final String GLOBALS_MUST_BE_DICT = "%s() globals must be a dict, not %p";
240-
public static final String GOT_INVALID_CODESTRING = "got an invalid codestring trying to create a function code object";
241236
public static final String GOT_MULTIPLE_VALUES_FOR_ARG = "%s() got multiple values for argument '%s'";
242237
public static final String GOT_SOME_POS_ONLY_ARGS_PASSED_AS_KEYWORD = "%s() got some positional-only arguments passed as keyword arguments: '%s'";
243238
public static final String GOT_UNEXPECTED_KEYWORD_ARG = "%s() got an unexpected keyword argument '%s'";
@@ -380,16 +375,13 @@ public abstract class ErrorMessages {
380375
public static final String NONLOCAL_AND_GLOBAL = "name '%s' is nonlocal and global";
381376
public static final String NONLOCAL_AT_MODULE_LEVEL = "nonlocal declaration not allowed at module level";
382377
public static final String NON_HEX_DIGIT_FOUND = "Non-hexadecimal digit found";
383-
public static final String NON_STRING_IN_CODE_SLOT = "non-string found in code slot";
384378
public static final String NOT_A_ZIP_FILE = "not a Zip file: '%s'";
385379
public static final String NOT_ALL_ARGS_CONVERTED_DURING_FORMATTING = "not all arguments converted during %s formatting";
386-
public static final String NOT_ALLOWED_S_S_FORMAT_SPECIFIERS_S = "%s not allowed %s%s format specifier%s";
387380
public static final String NOT_ENOUGH_ARGS_FOR_FORMAT_STRING = "not enough arguments for format string";
388381
public static final String NOT_ENOUGH_VALUES_TO_UNPACK = "not enough values to unpack (expected %d, got %d)";
389382
public static final String NOT_SUPPORTED_BETWEEN_INSTANCES = "'%s' not supported between instances of '%p' and '%p'";
390383
public static final String NUMBER_S_CANNOT_FIT_INTO_INDEXSIZED_INT = "number %s cannot fit into index-sized integer";
391384
public static final String OBJ_INDEX_MUST_BE_INT_OR_SLICES = "%s indices must be integers or slices, not %p";
392-
public static final String OBJ_CANNOT_BE_INTERPRETED_AS_INT = "%s cannot be interpreted as int (type %p)";
393385
public static final String OBJ_CANNOT_BE_INTERPRETED_AS_INTEGER = "'%p' object cannot be interpreted as an int";
394386
public static final String OBJ_DOES_NOT_SUPPORT_INDEXING = "'%s' object does not support indexing";
395387
public static final String OBJ_DOES_NOT_SUPPORT_ITEM_ASSIGMENT = "'%s' object does not support item assignment";
@@ -420,7 +412,6 @@ public abstract class ErrorMessages {
420412
public static final String PYTHON_INT_TOO_LARGE_TO_CONV_TO = "Python int too large to convert to %s";
421413
public static final String PYTHON_INT_TOO_LARGE_TO_CONV_TO_C_TYPE = "Python int too large to convert to %s-byte C type";
422414
public static final String RANGE_OUT_OF_BOUNDS = "range index out of range";
423-
public static final String RANGE_DOES_NOT_SUPPORT = "range does not support %s, %s, %s";
424415
public static final String RAW_FORMAT_NOT_SUPPORTED = "RAW format unsupported";
425416
public static final String READ_BYTE_OUT_OF_RANGE = "read byte out of range";
426417
public static final String READ_WRITE_BYTELIKE_OBJ = "read-write bytes-like object";
@@ -434,13 +425,11 @@ public abstract class ErrorMessages {
434425
public static final String C_REQUIRES_INT_IN_BYTE_RANGE_OR_SINGLE_BYTE = "%%c requires an integer in range(256) or a single byte";
435426
public static final String REQUIRES_OBJ_THAT_IMPLEMENTS_S = " %%r requires an object that implements %s";
436427
public static final String REQUIRES_STRING_AS_LEFT_OPERAND = "'in <string>' requires string as left operand, not %P";
437-
public static final String RESULT_TOO_MANY_ITEMS = "%s result has too many items";
438428
public static final String RETURN_OUTSIDE_FUNC = "'return' outside function";
439429
public static final String S_RETURNED_BASE_WITH_UNSUITABLE_LAYOUT = "%s returned base with unsuitable layout ('%p')";
440430
public static final String RETURNED_NON_FLOAT = "%p.%s returned non-float (type %p)";
441431
public static final String RETURNED_NON_INT = "%s returned a non-int (type %p)";
442432
public static final String S_RETURNED_NON_CLASS = "%s returned a non-class ('%p')";
443-
public static final String P_S_RETURNED_NON_INT = "%p.%s returned a non int (type %p)";
444433
public static final String RETURNED_NON_INTEGER = "%s returned a non-integer";
445434
public static final String RETURNED_NON_INTEGRAL = "%s returned non-Integral (type %p)";
446435
public static final String RETURNED_NON_LONG = "%p.%s returned a non long (type %p)";
@@ -495,7 +484,6 @@ public abstract class ErrorMessages {
495484
public static final String TUPLE_ASSIGN_OUT_OF_BOUNDS = "tuple assignment index out of range";
496485
public static final String TUPLE_OUT_OF_BOUNDS = "tuple index out of range";
497486
public static final String TUPLE_OR_STRUCT_TIME_ARG_REQUIRED = "Tuple or struct_time argument required";
498-
public static final String TWO_STARRED_EXPRESSION_IN_ASSIGMENT = "two starred expressions in assignment";
499487
public static final String TYPE_DOES_NOT_PROVIDE_BASES = "type does not provide bases";
500488
public static final String TYPE_DOESNT_DEFINE_METHOD = "type %p doesn't define %s method";
501489
public static final String TYPE_IS_NOT_ACCEPTABLE_BASE_TYPE = "type '%p' is not an acceptable base type";
@@ -544,11 +532,14 @@ public abstract class ErrorMessages {
544532
public static final String POW_BASE_NOT_INVERTIBLE = "base is not invertible for the given modulus";
545533
public static final String POW_ZERO_CANNOT_RAISE_TO_NEGATIVE_POWER = "0.0 cannot be raised to a negative power";
546534
public static final String S_ALIGNMENT_FLAG_NOT_ALLOWED_FOR_COMPLEX_FMT = "'%c' alignment flag is not allowed in complex format specifier";
535+
public static final String EQUALS_ALIGNMENT_FLAG_NOT_ALLOWED_FOR_STRING_FMT = "'=' alignment not allowed in string format specifier";
547536
public static final String ZERO_PADDING_NOT_ALLOWED_FOR_COMPLEX_FMT = "Zero padding is not allowed in complex format specifier";
548537
public static final String POW_THIRD_ARG_CANNOT_BE_ZERO = "pow() 3rd argument cannot be 0";
549538
public static final String CANNOT_ENCODE_DOCSTR = "'utf-8' codec can't encode docstring '%s'";
550539
public static final String PRECISION_NOT_ALLOWED_FOR_INT = "Precision not allowed in integer format specifier";
551540
public static final String SIGN_NOT_ALLOWED_WITH_C_FOR_INT = "Sign not allowed with integer format specifier 'c'";
541+
public static final String ALTERNATE_NOT_ALLOWED_WITH_C_FOR_INT = "Alternate form (#) not allowed with integer format specifier 'c'";
542+
public static final String ALTERNATE_NOT_ALLOWED_WITH_STRING_FMT = "Alternate form (#) not allowed in string format specifier";
552543
public static final String CAPI_LOAD_ERROR = "Could not load C API from %s.";
553544
public static final String NATIVE_ACCESS_NOT_ALLOWED = "Cannot run any C extensions because native access is not allowed.";
554545
public static final String HPY_LOAD_ERROR = "Could not load HPy C API from %s.";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/formatting/ComplexFormatter.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,17 @@ protected ComplexFormatter(PythonCore core, FormattingBuffer result, Spec spec)
5454
Spec imSpec;
5555
if (hasNoSpecType()) {
5656
// no type spec: should be like the default __str__
57-
reSpec = getComponentSpecForNoSpecType(InternalFormat.Spec.NONE);
58-
imSpec = getComponentSpecForNoSpecType('+');
57+
reSpec = getComponentSpecForNoSpecType(spec, InternalFormat.Spec.NONE);
58+
imSpec = getComponentSpecForNoSpecType(spec, '+');
5959
} else {
6060
// Turn off any flags that should apply to the result as a whole and not to the
61-
// individual
62-
// components (re/im). Sign of re is determined by the sign flag, sign of im will be
63-
// always
64-
// printed ('+' flag)
61+
// individual components (re/im). Sign of re is determined by the sign flag, sign of im
62+
// will be always printed ('+' flag)
6563
reSpec = getComponentSpec(spec, spec.sign);
6664
imSpec = getComponentSpec(spec, '+');
6765
}
68-
reFormatter = new FloatFormatter(core, result, reSpec);
69-
imFormatter = new FloatFormatter(core, result, imSpec);
66+
reFormatter = new FloatFormatter(core, result, reSpec, false);
67+
imFormatter = new FloatFormatter(core, result, imSpec, false);
7068
}
7169

7270
public ComplexFormatter(PythonCore core, Spec spec) {
@@ -85,10 +83,17 @@ private static Spec getComponentSpec(Spec spec, char sign) {
8583
spec.type);
8684
}
8785

88-
private static Spec getComponentSpecForNoSpecType(char sign) {
86+
private static Spec getComponentSpecForNoSpecType(Spec spec, char sign) {
8987
// CPython uses "r" type, but also some internal flags that cause that integer values
9088
// are printed without the decimal part, which is mostly what "g" does
91-
return new InternalFormat.Spec(' ', '>', sign, false, InternalFormat.Spec.UNSPECIFIED, Spec.NONE, -1, 'g');
89+
int precision = spec.precision;
90+
char type = 'r';
91+
if (precision < 0) {
92+
precision = 0;
93+
} else {
94+
type = 'g';
95+
}
96+
return new InternalFormat.Spec(' ', '>', sign, false, InternalFormat.Spec.UNSPECIFIED, Spec.NONE, precision, type);
9297
}
9398

9499
private boolean hasNoSpecType() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/formatting/FloatFormatter.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,16 @@ public class FloatFormatter extends InternalFormat.Formatter {
4646
*
4747
* @param result destination buffer
4848
* @param spec parsed conversion specification
49+
* @param addDot0 reflects flag {@code Py_DTSF_ADD_DOT_0} in CPython, applicable only for 'r'
50+
* specifier
4951
*/
50-
public FloatFormatter(PythonCore core, FormattingBuffer result, Spec spec) {
52+
public FloatFormatter(PythonCore core, FormattingBuffer result, Spec spec, boolean addDot0) {
5153
super(core, result, spec);
52-
if (spec.alternate) {
54+
if (!addDot0 && spec.type == 'r') {
55+
minFracDigits = 0;
56+
} else if (spec.alternate) {
5357
// Alternate form means do not trim the zero fractional digits.
58+
// This should be equivalent to Py_DTSF_ALT flag in CPython
5459
minFracDigits = -1;
5560
} else if (spec.type == 'r' || spec.type == Spec.NONE) {
5661
// These formats by default show at least one fractional digit.
@@ -64,11 +69,10 @@ public FloatFormatter(PythonCore core, FormattingBuffer result, Spec spec) {
6469
}
6570
}
6671

67-
/**
68-
* Construct the formatter from a specification, allocating a buffer internally for the result.
69-
*
70-
* @param spec parsed conversion specification
71-
*/
72+
public FloatFormatter(PythonCore core, FormattingBuffer result, Spec spec) {
73+
this(core, result, spec, true);
74+
}
75+
7276
public FloatFormatter(PythonCore core, Spec spec) {
7377
this(core, new FormattingBuffer.StringFormattingBuffer(size(spec)), spec);
7478
}
@@ -646,11 +650,10 @@ private void appendFixed(CharSequence digits, int exp, int precision) {
646650
}
647651
lenWhole = digitCount;
648652
}
649-
650-
if (noTruncate) {
651-
// Extend the fraction as BigDecimal will have economised on zeros.
652-
appendPointAndTrailingZeros(precision - digitCount);
653-
}
653+
}
654+
if (noTruncate) {
655+
// Extend the fraction as BigDecimal will have economised on zeros.
656+
appendPointAndTrailingZeros(lenFraction + precision - digitCount);
654657
}
655658

656659
// Finally, ensure we have all and only the fractional digits we should.

0 commit comments

Comments
 (0)