Fixed bug with FORMAT_VALUE where a sub expression would not be correctly interpreted

This commit is contained in:
DanielBradburn
2016-08-16 08:24:06 +02:00
parent 2bd850f297
commit 004ce5c491
2 changed files with 20 additions and 13 deletions

View File

@@ -1,3 +1,5 @@
# std
import os
# test
import pytest
import hypothesis
@@ -85,19 +87,20 @@ def fstrings(draw):
:return: A valid f-string.
"""
prefix = draw(st.sampled_from('f'))
raw = draw(st.sampled_from(list('r') + ['']))
is_raw = draw(st.booleans())
integer_strategy = st.integers(min_value=0, max_value=3)
expression_count = draw(integer_strategy)
content = []
for _ in range(expression_count):
expression = draw(expressions())
#conversion = draw(st.sampled_from(('', '!s', '!r', '!a',)))
#specifier = draw(st.sampled_from(format_specifiers(), st.just('')))
content.append('{{{}}}'.format(expression))
# not yet : conversion not supported
conversion = ''#draw(st.sampled_from(('', '!s', '!r', '!a',)))
has_specifier = draw(st.booleans())
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
content.append('{{{}{}}}'.format(expression, conversion, specifier))
content = ''.join(content)
return "{}{}'{}'".format(prefix, raw, content)
return "f{}'{}'".format('r' if is_raw else '', content)
@hypothesis.given(format_specifiers())
@@ -110,11 +113,8 @@ def test_format_specifiers(format_specifier):
raise
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason="requires python3.6")
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
@hypothesis.given(fstrings())
@hypothesis.example("f'{abc}'") # BUG: strings with a single expression do not uncompyle correctly.
@hypothesis.example("fr'{abc}{xyz}'") # BUG: no support for raw f strings.
@hypothesis.example("f'{len(items)}{abc}'") # BUG: more complicated expressions than LOAD_NAME don't work
def test_uncompyle_fstring(fstring):
"""Verify uncompyling fstring bytecode"""
@@ -122,8 +122,14 @@ def test_uncompyle_fstring(fstring):
# no expressions just gets compiled to a normal string.
hypothesis.assume('{' in fstring)
# BUG : At the moment a single expression is not supported
# for example f'{abc}'.
hypothesis.assume(fstring.count('{') > 1)
expr = fstring + '\n'
code = compile(expr, '<string>', 'single')
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
recompiled = compile(deparsed.text, '<string>', 'single')
assert deparsed.text == expr
if recompiled != code:
assert deparsed.text == expr

View File

@@ -461,8 +461,8 @@ class Python3Parser(PythonParser):
elif opname == 'FORMAT_VALUE':
# Python 3.6+
self.addRule("""
formatted_value ::= LOAD_FAST FORMAT_VALUE
formatted_value ::= LOAD_NAME FORMAT_VALUE
formatted_value ::= expr FORMAT_VALUE
formatted_value ::= expr FORMAT_VALUE
str ::= LOAD_CONST
formatted_value_or_str ::= formatted_value
formatted_value_or_str ::= str
@@ -492,6 +492,7 @@ class Python3Parser(PythonParser):
rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname))
self.add_unique_rule(rule, opname, token.attr, customize)
if opname_base == 'BUILD_LIST' and saw_format_value:
saw_format_value = False
format_or_str_n = "formatted_value_or_str_%s" % v
self.addRule("""
expr ::= joined_str