Kaydet (Commit) c72349f3 authored tarafından Felix Yan's avatar Felix Yan Kaydeden (comit) Berker Peksag

Fix string parsing with newline (#123)

When looping over a joined str, if a node is ast.Str and the value is
just a newline "\n", the write() function adds an additional indentation
after it, which fails to represent the original string. By calling
self.result.append() here directly the issue is resolved.

The added test could show the issue. With code_gen unmodifed, it fails
with the following error:

```
AssertionError: "if 1:\n    x = f'{host}\\n\\t{port}\\n    '" != "if
1:\n    x = f'{host}\\n\\t{port}\\n'"
  if 1:
      -     x = f'{host}\n\t{port}\n    '?
      ----
      +     x = f'{host}\n\t{port}\n'
```

Which is exactly the problem.

This fixes parsing issues with many of Python 3.7's stdlib. Namely the
following ones:

/usr/lib/python3.7/warnings.py
/usr/lib/python3.7/netrc.py
/usr/lib/python3.7/test/test_embed.py
/usr/lib/python3.7/test/support/testresult.py
/usr/lib/python3.7/idlelib/grep.py

Fixes #119
üst a3c9e284
......@@ -14,3 +14,4 @@ And with some modifications based on Armin's code:
* Lenny Truong <leonardtruong@protonmail.com>
* Radomír Bosák <radomir.bosak@gmail.com>
* Kodi Arfer <git@arfer.net>
* Felix Yan <felixonmars@archlinux.org>
......@@ -168,8 +168,6 @@ class SourceGenerator(ExplicitNodeVisitor):
visit(item)
elif callable(item):
item()
elif item == '\n':
newline()
else:
if self.new_lines:
append('\n' * self.new_lines)
......@@ -220,7 +218,7 @@ class SourceGenerator(ExplicitNodeVisitor):
def else_body(self, elsewhat):
if elsewhat:
self.write('\n', 'else:')
self.write(self.newline, 'else:')
self.body(elsewhat)
def body_or_else(self, node):
......@@ -359,7 +357,7 @@ class SourceGenerator(ExplicitNodeVisitor):
if len(else_) == 1 and isinstance(else_[0], ast.If):
node = else_[0]
set_precedence(node, node.test)
self.write('\n', 'elif ', node.test, ':')
self.write(self.newline, 'elif ', node.test, ':')
self.body(node.body)
else:
self.else_body(else_)
......
......@@ -71,7 +71,7 @@ def wrap_line(line, maxline=79, result=[], count=count):
indentation = line[0]
lenfirst = len(indentation)
indent = lenfirst - len(indentation.strip())
indent = lenfirst - len(indentation.lstrip())
assert indent in (0, lenfirst)
indentation = line.pop(0) if indent else ''
......
......@@ -13,9 +13,14 @@ New features
Bug fixes
~~~~~~~~~
* Fix string parsing when there is a newline inside an f-string. (Reported by
Adam Cécile in `Issue 119`_ and fixed by Felix Yan in `PR 123`_.)
* Fixed code generation with escaped braces in f-strings.
(Reported by Felix Yan in `Issue 124`_ and fixed by Kodi Arfer in `PR 125`_.)
.. _`Issue 119`: https://github.com/berkerpeksag/astor/issues/119
.. _`PR 123`: https://github.com/berkerpeksag/astor/pull/123
.. _`Issue 124`: https://github.com/berkerpeksag/astor/issues/124
.. _`PR 125`: https://github.com/berkerpeksag/astor/pull/125
......
......@@ -516,6 +516,11 @@ class CodegenTestCase(unittest.TestCase, Comparisons):
x = f"""{host}\n\t{port}\n"""
'''
self.assertSrcRoundtripsGtVer(source, (3, 6))
source = '''
if 1:
x = f'{host}\\n\\t{port}\\n'
'''
self.assertSrcRoundtripsGtVer(source, (3, 6))
def test_fstring_escaped_braces(self):
source = '''
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment