Skip to content
This repository has been archived by the owner on May 31, 2020. It is now read-only.

Format and f-string support (and minor other changes) #952

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions build-android.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
<fail message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir" />

<fail message="android.jar not found at ${sdk.dir}/platforms/${target.platform}/, is your ANDROID_TARGET set?">
<condition>
<not>
<available file="${sdk.dir}/platforms/${target.platform}/android.jar"/>
</not>
</condition>
</fail>

<target name="compile" description="Compile the Android-specific source">
<mkdir dir="${build}/android"/>
<javac debug="true"
Expand Down
2 changes: 1 addition & 1 deletion python/common/org/Python.java
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ public static org.python.Object filter(org.python.Object function, org.python.Ob
)
public static org.python.types.Str format(org.python.Object value, org.python.Object format_spec) {
if (format_spec == null) {
return (org.python.types.Str) value.__str__();
return (org.python.types.Str) value.__format__(new org.python.types.Str(""));
} else {
return (org.python.types.Str) value.__format__(format_spec);
}
Expand Down
2 changes: 1 addition & 1 deletion python/common/org/python/Object.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public interface Object extends Comparable {
public org.python.Object __str__();

public org.python.Object __bytes__();
public org.python.Object __format__(org.python.Object format);
public org.python.Object __format__(org.python.Object format_spec);

public org.python.Object __lt__(org.python.Object other);
public org.python.Object __le__(org.python.Object other);
Expand Down
7 changes: 0 additions & 7 deletions python/common/org/python/types/Bool.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,6 @@ public org.python.types.Str __repr__() {
}
}

@org.python.Method(
__doc__ = ""
)
public org.python.types.Str __format__(org.python.Object format_string) {
throw new org.python.exceptions.NotImplementedError("'bool'.__format__ has not been implemented.");
}

@org.python.Method(
__doc__ = "",
args = {"index", "value"}
Expand Down
6 changes: 0 additions & 6 deletions python/common/org/python/types/ByteArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -592,12 +592,6 @@ public org.python.Object __contains__(org.python.Object slice) {
return new Bytes(this.value).__contains__(slice);
}

@org.python.Method(
__doc__ = "default object formatter"
)
public org.python.types.Str __format__(java.util.List<org.python.Object> args, java.util.Map<java.lang.String, org.python.Object> kwargs, java.util.List<org.python.Object> default_args, java.util.Map<java.lang.String, org.python.Object> default_kwargs) {
throw new org.python.exceptions.NotImplementedError("bytearray.__format__ has not been implemented.");
}

@org.python.Method(
__doc__ = ""
Expand Down
6 changes: 0 additions & 6 deletions python/common/org/python/types/Bytes.java
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,6 @@ public org.python.Object __contains__(org.python.Object slice) {
return org.python.types.Bool.FALSE;
}

@org.python.Method(
__doc__ = "default object formatter"
)
public org.python.types.Str __format__(java.util.List<org.python.Object> args, java.util.Map<java.lang.String, org.python.Object> kwargs, java.util.List<org.python.Object> default_args, java.util.Map<java.lang.String, org.python.Object> default_kwargs) {
throw new org.python.exceptions.NotImplementedError("bytes.__format__ has not been implemented.");
}

@org.python.Method(
__doc__ = "Return self>=value.",
Expand Down
72 changes: 36 additions & 36 deletions python/common/org/python/types/Complex.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,39 +161,49 @@ private String partToStr(org.python.types.Float x) {
__doc__ = "Return repr(self)."
)
public org.python.Object __repr__() {
java.lang.StringBuilder buffer = new java.lang.StringBuilder();
boolean real_present = true;
if (this.real.value != 0) {
buffer.append("(");
if (((org.python.types.Bool) ((this.real).__int__().__eq__(this.real))).value) {
buffer.append(((org.python.types.Str) this.real.__int__().__repr__()).value);
} else {
buffer.append(((org.python.types.Str) this.real.__repr__()).value);
}

if (this.real.value != 0.0 || this.real.isNegativeZero()) {
return new org.python.types.Str("(" + partToStr(this.real) + ((this.imag.value >= 0.0 && !this.imag.isNegativeZero()) ? "+" : "-") + partToStr(new org.python.types.Float(Math.abs(this.imag.value))) + "j)");
} else {
real_present = false;
return new org.python.types.Str(partToStr(this.imag) + "j");
}
if (this.real.value != 0 && this.imag.value >= 0) {

}


@org.python.Method(
__doc__ = "complex.__format__() -> str\n\nConvert to a string according to format_spec.",
args={"format_spec"}
)
public org.python.Object __format__(org.python.Object format_spec) {
String fs = ((org.python.types.Str) format_spec).value;


if(!(fs.endsWith("f")
||fs.endsWith("F")
||fs.endsWith("g")
||fs.endsWith("G")
||fs.endsWith("e")
||fs.endsWith("E")
||fs.endsWith("n")
)){
//format specs are ignored by python for complex numbers if no floatingpoit spec is present
return this.__repr__();
}
// use the floating point spec

java.lang.StringBuilder buffer = new java.lang.StringBuilder();

buffer.append(((org.python.types.Str) this.real.__format__(format_spec)).value);

if (this.imag.value >= 0) {
buffer.append("+");
}
if (((org.python.types.Bool) ((this.imag).__int__().__eq__(this.imag))).value) {
buffer.append(((org.python.types.Str) (this.imag).__int__().__repr__()).value);
} else {
buffer.append(((org.python.types.Str) (this.imag).__repr__()).value);
}
buffer.append(((org.python.types.Str) (this.imag).__format__(format_spec)).value);
buffer.append("j");
if (real_present) {
buffer.append(")");
}
return new org.python.types.Str(buffer.toString());
}

@org.python.Method(
__doc__ = "complex.__format__() -> str\n\nConvert to a string according to format_spec."
)
public org.python.Object __format__(org.python.Object format_string) {
throw new org.python.exceptions.NotImplementedError("complex.__format__ has not been implemented.");
}
}

@org.python.Method(
__doc__ = "Return self<value.",
Expand Down Expand Up @@ -302,16 +312,6 @@ public org.python.Object __sub__(org.python.Object other) {
throw new org.python.exceptions.TypeError("unsupported operand type(s) for -: 'complex' and '" + other.typeName() + "'");
}

@org.python.Method(
__doc__ = "Return str(self)."
)
public org.python.Object __str__() {
if (this.real.value != 0.0 || this.real.isNegativeZero()) {
return new org.python.types.Str("(" + partToStr(this.real) + ((this.imag.value >= 0.0 && !this.imag.isNegativeZero()) ? "+" : "-") + partToStr(new org.python.types.Float(Math.abs(this.imag.value))) + "j)");
} else {
return new org.python.types.Str(partToStr(this.imag) + "j");
}
}

@org.python.Method(
__doc__ = "Return self*value.",
Expand Down
7 changes: 0 additions & 7 deletions python/common/org/python/types/Dict.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,6 @@ public org.python.types.Str __repr__() {
return new org.python.types.Str(buffer.toString());
}

@org.python.Method(
__doc__ = "default object formatter"
)
public org.python.types.Str __format__(org.python.Object other) {
throw new org.python.exceptions.NotImplementedError("dict.__format__() has not been implemented.");
}

@org.python.Method(
__doc__ = ""
)
Expand Down
6 changes: 0 additions & 6 deletions python/common/org/python/types/DictKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ public org.python.types.Str __repr__() {
return new org.python.types.Str(buffer.toString());
}

@org.python.Method(
__doc__ = "default object formatter"
)
public org.python.types.Str __format__(org.python.Object other) {
throw new org.python.exceptions.NotImplementedError(this.typeName() + ".__format__() has not been implemented.");
}

@org.python.Method(
__doc__ = "__dir__() -> list\ndefault dir() implementation"
Expand Down
7 changes: 0 additions & 7 deletions python/common/org/python/types/DictValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,6 @@ public org.python.types.Str __repr__() {
return new org.python.types.Str(buffer.toString());
}

@org.python.Method(
__doc__ = "default object formatter"
)
public org.python.types.Str __format__(org.python.Object other) {
throw new org.python.exceptions.NotImplementedError(this.typeName() + ".__format__() has not been implemented.");
}

@org.python.Method(
__doc__ = "__dir__() -> list\ndefault dir() implementation"
)
Expand Down
123 changes: 76 additions & 47 deletions python/common/org/python/types/Float.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,41 @@ public Float(org.python.Object[] args, java.util.Map<java.lang.String, org.pytho
__doc__ = "Return repr(self)."
)
public org.python.types.Str __repr__() {
String format = ".17g";
return this.__format__(new org.python.types.Str(format));
}

@org.python.Method(
__doc__ = ""
)
public boolean isNegativeZero() {
return Double.doubleToRawLongBits(this.value) == NEGATIVE_ZERO_RAW_BITS;
}

@org.python.Method(
__doc__ = "float.__format__(format_spec) -> string\n\nFormats the float according to format_spec.",
args = {"format_spec"}
)
public org.python.types.Str __format__(org.python.Object format_spec) {
String format = ((org.python.types.Str) format_spec).value;
if(format.endsWith("%")){
org.python.types.Str new_format = new org.python.types.Str(format.substring(0,-1)+"f");
org.python.types.Float new_float = new org.python.types.Float(this.value*100);
return new_float.__format__(new_format);
}
if(format.endsWith("n")){
throw new org.python.exceptions.NotImplementedError("float formatting with 'n' formatter has not been implemented.");
}
if(format.length() == 0 || !Character.isLetter(format.charAt(format.length()-1))){
// use g as default formatter
if(format.indexOf('.') <0){
// if no precision is given use .17
format += ".17g";
}else{
format += "g";
}
}
// handle e, E, f, F, g, G or None formatters
double value = this.value;
String result;
if (Double.isNaN(value)) {
Expand All @@ -70,56 +105,50 @@ public org.python.types.Str __repr__() {
result = "-inf";
}
} else {
String format = "%.17g";
result = String.format(Locale.US, format, value);
int dot_pos = result.indexOf(".");
int e_pos = result.indexOf("e");
if (dot_pos != -1) {
// Remove trailing zeroes in the fractional part
int last_zero = -1;
int i;
for (i = dot_pos + 1; i < result.length(); i++) {
char c = result.charAt(i);
if (i == e_pos) {
break;
} else if (c == '0') {
if (last_zero == -1) {
last_zero = i;
}
} else {
last_zero = -1;
}
}
if (last_zero != -1) {
if (last_zero == dot_pos + 1) {
// Everything after the dot is zeros
if (e_pos == -1) {
// If there's no "e", leave ".0" at the end
last_zero += 1;
} else {
// If there is an "e", nuke the dot as well
last_zero -= 1;
}
}
result = result.substring(0, last_zero) + result.substring(i);
}
}
result = String.format(Locale.US, "%"+format, value);
if(format.endsWith("g")
|| format.endsWith("G")){

// Check whether we need to remove trailing zeros when not using g or G as a formatter
int dot_pos = result.indexOf(".");
int e_pos = result.indexOf("e");
if (dot_pos != -1) {
// Remove trailing zeroes in the fractional part
int last_zero = -1;
int i;
for (i = dot_pos + 1; i < result.length(); i++) {
char c = result.charAt(i);
if (i == e_pos) {
break;
} else if (c == '0') {
if (last_zero == -1) {
last_zero = i;
}
} else {
last_zero = -1;
}
}
if (last_zero != -1) {
if (last_zero == dot_pos + 1) {
// Everything after the dot is zeros
if (e_pos == -1) {
// If there's no "e", leave ".0" at the end
last_zero += 1;
} else {
// If there is an "e", nuke the dot as well
last_zero -= 1;
}
}
result = result.substring(0, last_zero) + result.substring(i);
}
}
}
}
if(format.endsWith("G")|| format.endsWith("F") || format.endsWith("E")){
result = result.toUpperCase();
}
return new org.python.types.Str(result);
}

@org.python.Method(
__doc__ = ""
)
public boolean isNegativeZero() {
return Double.doubleToRawLongBits(this.value) == NEGATIVE_ZERO_RAW_BITS;
}

@org.python.Method(
__doc__ = "float.__format__(format_spec) -> string\n\nFormats the float according to format_spec."
)
public org.python.types.Str __format__(org.python.Object format_string) {
throw new org.python.exceptions.NotImplementedError("float.__format__() has not been implemented.");
}

@org.python.Method(
Expand Down
22 changes: 19 additions & 3 deletions python/common/org/python/types/Int.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.python.types;

import java.util.Locale;

public class Int extends org.python.types.Object {
public long value;

Expand Down Expand Up @@ -128,10 +130,24 @@ public org.python.types.Str __repr__() {
}

@org.python.Method(
__doc__ = ""
__doc__ = "",
args = {"format_spec"}
)
public org.python.types.Str __format__(org.python.Object format_str) {
throw new org.python.exceptions.NotImplementedError("int.__format__() has not been implemented");
public org.python.types.Str __format__(org.python.Object format_spec) {

String fs = ((org.python.types.Str) format_spec).value;
if(fs.endsWith("n"))
throw new org.python.exceptions.NotImplementedError("int formatting with 'n' as formatter has not been implemented");
if(fs.endsWith("b"))
throw new org.python.exceptions.NotImplementedError("int formatting with 'b' as formatter has not been implemented");

if(fs.length() == 0 || !Character.isLetter(fs.charAt(fs.length()-1))){
// use d as default formatter
fs += "d";
}


return new org.python.types.Str(String.format(Locale.US,"%"+fs,this.value));
}

@org.python.Method(
Expand Down
7 changes: 0 additions & 7 deletions python/common/org/python/types/List.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,6 @@ public org.python.types.Str __repr__() {
return new org.python.types.Str(buffer.toString());
}

@org.python.Method(
__doc__ = "default object formatter"
)
public org.python.types.Str __format__() {
throw new org.python.exceptions.NotImplementedError("list.__format__() has not been implemented.");
}

@org.python.Method(
__doc__ = "Return self<value.",
args = {"other"}
Expand Down
Loading