summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2020-05-08 14:21:51 +0200
committerStefan Behnel <stefan_ml@behnel.de>2020-05-08 14:21:51 +0200
commitb410599275459005e1b005459687ccbfea6e7b53 (patch)
tree9c05a7ca2abd8f7b7648035bd3ce040dbe3f54e8
parent6d3098246e93baef7d825ca7cf02b49bc6cb53b7 (diff)
downloadcython-gh3092_percent_d_format.tar.gz
Fix optimised string formatting when '%d' argument is a float object, which does not support '{x:d}' formatting.gh3092_percent_d_format
Closes https://github.com/cython/cython/issues/3092
-rw-r--r--Cython/Compiler/ExprNodes.py3
-rw-r--r--Cython/Compiler/Optimize.py7
-rw-r--r--tests/run/fstring.pyx18
3 files changed, 19 insertions, 9 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index 895ff3fe2..f4c677436 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -3293,7 +3293,7 @@ class FormattedValueNode(ExprNode):
# {}-delimited portions of an f-string
#
# value ExprNode The expression itself
- # conversion_char str or None Type conversion (!s, !r, !a, or none)
+ # conversion_char str or None Type conversion (!s, !r, !a, or none, or 'd' for integer conversion)
# format_spec JoinedStrNode or None Format string passed to __format__
# c_format_spec str or None If not None, formatting can be done at the C level
@@ -3308,6 +3308,7 @@ class FormattedValueNode(ExprNode):
's': 'PyObject_Unicode',
'r': 'PyObject_Repr',
'a': 'PyObject_ASCII', # NOTE: mapped to PyObject_Repr() in Py2
+ 'd': '__Pyx_PyNumber_IntOrLong', # NOTE: internal mapping for '%d' formatting
}.get
def may_be_none(self):
diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py
index 4e6149c07..b8e1cee2e 100644
--- a/Cython/Compiler/Optimize.py
+++ b/Cython/Compiler/Optimize.py
@@ -4382,14 +4382,19 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
break
if format_type in u'asrfdoxX':
format_spec = s[1:]
+ conversion_char = None
if format_type in u'doxX' and u'.' in format_spec:
# Precision is not allowed for integers in format(), but ok in %-formatting.
can_be_optimised = False
elif format_type in u'ars':
format_spec = format_spec[:-1]
+ conversion_char = format_type
+ elif format_type == u'd':
+ # '%d' formatting supports float, but '{obj:d}' does not => convert to int first.
+ conversion_char = 'd'
substrings.append(ExprNodes.FormattedValueNode(
arg.pos, value=arg,
- conversion_char=format_type if format_type in u'ars' else None,
+ conversion_char=conversion_char,
format_spec=ExprNodes.UnicodeNode(
pos, value=EncodedString(format_spec), constant_result=format_spec)
if format_spec else None,
diff --git a/tests/run/fstring.pyx b/tests/run/fstring.pyx
index 574d56fa3..30aa7fe01 100644
--- a/tests/run/fstring.pyx
+++ b/tests/run/fstring.pyx
@@ -533,31 +533,35 @@ def format_decoded_bytes(bytes value):
"//FormattedValueNode",
"//JoinedStrNode",
)
-def generated_fstring(int i, unicode u not None, o):
+def generated_fstring(int i, float f, unicode u not None, o):
"""
- >>> i, u, o = 11, u'xyz', [1]
+ >>> i, f, u, o = 11, 1.3125, u'xyz', [1]
>>> print(((
... u"(i) %s-%.3s-%r-%.3r-%d-%3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
... u"(u) %s-%.2s-%r-%.7r %% "
- ... u"(o) %s-%.2s-%r-%.2r"
+ ... u"(o) %s-%.2s-%r-%.2r %% "
+ ... u"(f) %.2f-%d"
... ) % (
... i, i, i, i, i, i, i, i, i, i, i, i, i, i,
... u, u, u, u,
... o, o, o, o,
+ ... f, f,
... )).replace("-u'xyz'", "-'xyz'"))
- (i) 11-11-11-11-11- 11-13-0013-b- b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz' % (o) [1]-[1-[1]-[1
+ (i) 11-11-11-11-11- 11-13-0013-b- b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz' % (o) [1]-[1-[1]-[1 % (f) 1.31-1
- >>> print(generated_fstring(i, u, o).replace("-u'xyz'", "-'xyz'"))
- (i) 11-11-11-11-11- 11-13-0013-b- b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz' % (o) [1]-[1-[1]-[1
+ >>> print(generated_fstring(i, f, u, o).replace("-u'xyz'", "-'xyz'"))
+ (i) 11-11-11-11-11- 11-13-0013-b- b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz' % (o) [1]-[1-[1]-[1 % (f) 1.31-1
"""
return (
u"(i) %s-%.3s-%r-%.3r-%d-%3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
u"(u) %s-%.2s-%r-%.7r %% "
- u"(o) %s-%.2s-%r-%.2r"
+ u"(o) %s-%.2s-%r-%.2r %% "
+ u"(f) %.2f-%d"
) % (
i, i, i, i, i, i, i, i, i, i, i, i, i, i,
u, u, u, u,
o, o, o, o,
+ f, f,
)