Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
32 changes: 32 additions & 0 deletions 32 Lib/lib2to3/fixer_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,38 @@ def ImportAndCall(node, results, names):
new.prefix = node.prefix
return new

def BlankLineOrPass(node):
"""Returns either a blank line or a pass statement depending on
the node's parent's siblings to maintain syntactic correctness
within a suite after conversion"""
skip = {token.NEWLINE, token.INDENT, token.DEDENT}
def has_significant_sibling(node, is_forward):
if is_forward:
sibling = node.next_sibling
else:
sibling = node.prev_sibling
while sibling:
if isinstance(sibling, Node):
if sibling.type != syms.simple_stmt:
return True
for child in sibling.children:
if child.type not in skip:
return True
elif isinstance(sibling, Leaf) and sibling.type not in skip:
return True
if is_forward:
sibling = sibling.next_sibling
else:
sibling = sibling.prev_sibling
return False

parent = node.parent
if parent and parent.parent and parent.parent.type == syms.suite:
if (not has_significant_sibling(parent, False)
and not has_significant_sibling(parent, True)):
return Name("pass")
return BlankLine()


###########################################################
### Determine whether a node represents a given literal
Expand Down
4 changes: 2 additions & 2 deletions 4 Lib/lib2to3/fixes/fix_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# Local imports
from .. import fixer_base
from ..fixer_util import BlankLine
from ..fixer_util import BlankLineOrPass

class FixFuture(fixer_base.BaseFix):
BM_compatible = True
Expand All @@ -17,6 +17,6 @@ class FixFuture(fixer_base.BaseFix):
run_order = 10

def transform(self, node, results):
new = BlankLine()
new = BlankLineOrPass(node)
new.prefix = node.prefix
return new
4 changes: 2 additions & 2 deletions 4 Lib/lib2to3/fixes/fix_itertools_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Local imports
from lib2to3 import fixer_base
from lib2to3.fixer_util import BlankLine, syms, token
from lib2to3.fixer_util import BlankLineOrPass, syms, token


class FixItertoolsImports(fixer_base.BaseFix):
Expand Down Expand Up @@ -52,6 +52,6 @@ def transform(self, node, results):
if (not (imports.children or getattr(imports, 'value', None)) or
imports.parent is None):
p = node.prefix
node = BlankLine()
node = BlankLineOrPass(node)
node.prefix = p
return node
215 changes: 209 additions & 6 deletions 215 Lib/lib2to3/tests/test_fixers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ def setUp(self, fix_list=None, fixer_pkg="lib2to3", options=None):
self.refactor.post_order):
fixer.log = self.fixer_log

def _check(self, before, after):
before = support.reformat(before)
after = support.reformat(after)
def _check(self, before, after, reformat=True):
if reformat:
before = support.reformat(before)
after = support.reformat(after)
tree = self.refactor.refactor_string(before, self.filename)
self.assertEqual(after, str(tree))
return tree

def check(self, before, after, ignore_warnings=False):
tree = self._check(before, after)
def check(self, before, after, ignore_warnings=False, reformat=True):
tree = self._check(before, after, reformat=reformat)
self.assertTrue(tree.was_changed)
if not ignore_warnings:
self.assertEqual(self.fixer_log, [])
Expand Down Expand Up @@ -3656,9 +3657,130 @@ def test_future(self):
a = """\n# comment"""
self.check(b, a)

def test_suite_try_blank(self):
b = (
"try:\n"
" from __future__ import with_statement\n"
" from sys import exit\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" \n"
" from sys import exit\n"
"except ImportError:\n"
" pass\n")
self.check(b, a, reformat=False) # to avoid dedent

def test_suite_try_pass(self):
b = (
"try:\n"
" from __future__ import with_statement\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" pass\n"
"except ImportError:\n"
" pass\n")
self.check(b, a)

def test_suite_if_blank(self):
b = (
"if sys.version_info < (3, 0):\n"
" from __future__ import with_statement\n"
" from sys import exit\n")
a = (
"if sys.version_info < (3, 0):\n"
" \n"
" from sys import exit\n")
self.check(b, a, reformat=False) # to avoid dedent

def test_suite_if_pass(self):
b = (
"if sys.version_info < (3, 0):\n"
" from __future__ import with_statement\n")
a = (
"if sys.version_info < (3, 0):\n"
" pass\n")
self.check(b, a) # to avoid dedent

def test_pass_with_comments(self):
b = (
"try:\n"
" # this comment\n"
" from __future__ import with_statement # that comment\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" # this comment\n"
" pass # that comment\n"
"except ImportError:\n"
" pass\n")
self.check(b, a)

def test_pass_with_newlines(self):
b = (
"try:\n"
" \n"
" \n"
" from __future__ import with_statement\n"
" \n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" \n"
" \n"
" pass\n"
" \n"
"except ImportError:\n"
" pass\n")
self.check(b, a)

def test_run_order(self):
self.assert_runs_after('print')


class Test_future_with_itertools_imports(FixerTestCase):

def setUp(self):
fix_list = ["future", "itertools_imports"]
super(Test_future_with_itertools_imports, self).setUp(fix_list)

def test_double_transform(self):
"""Note the difference between the two conversion results, due to
the fact that 'future' fixer runs last"""
b = (
"try:\n"
" from __future__ import with_statement\n"
" from itertools import imap\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" pass\n"
" \n"
"except ImportError:\n"
" pass\n")
self.check(b, a, reformat=False) # to avoid dedent

b = (
"try:\n"
" from itertools import imap\n"
" from __future__ import with_statement\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" \n"
" pass\n"
"except ImportError:\n"
" pass\n")
self.check(b, a, reformat=False) # to avoid dedent


class Test_itertools(FixerTestCase):
fixer = "itertools"

Expand Down Expand Up @@ -3784,11 +3906,92 @@ def test_ifilter_and_zip_longest(self):
a = "from itertools import bar, %s, foo" % (name,)
self.check(b, a)

def test_suite_try_blank(self):
b = (
"try:\n"
" from itertools import imap\n"
" from sys import exit\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" \n"
" from sys import exit\n"
"except ImportError:\n"
" pass\n")
self.check(b, a, reformat=False) # to avoid dedent

def test_suite_try_pass(self):
b = (
"try:\n"
" from itertools import imap\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" pass\n"
"except ImportError:\n"
" pass\n")
self.check(b, a)

def test_suite_if_blank(self):
b = (
"if sys.version_info < (3, 0):\n"
" from itertools import imap\n"
" from sys import exit\n")
a = (
"if sys.version_info < (3, 0):\n"
" \n"
" from sys import exit\n")
self.check(b, a, reformat=False) # to avoid dedent

def test_suite_if_pass(self):
b = (
"if sys.version_info < (3, 0):\n"
" from itertools import imap\n")
a = (
"if sys.version_info < (3, 0):\n"
" pass\n")
self.check(b, a) # to avoid dedent

def test_pass_with_comments(self):
b = (
"try:\n"
" # this comment\n"
" from itertools import imap # that comment\n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" # this comment\n"
" pass # that comment\n"
"except ImportError:\n"
" pass\n")
self.check(b, a)

def test_pass_with_newlines(self):
b = (
"try:\n"
" \n"
" \n"
" from itertools import imap\n"
" \n"
"except ImportError:\n"
" pass\n")
a = (
"try:\n"
" \n"
" \n"
" pass\n"
" \n"
"except ImportError:\n"
" pass\n")
self.check(b, a)

def test_import_star(self):
s = "from itertools import *"
self.unchanged(s)


def test_unchanged(self):
s = "from itertools import foo"
self.unchanged(s)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Transformation performed by certain fixers (e.g. future, itertools_imports) that causes a statement to be replaced by a blank line will generate a Python file that contains a syntax error. Enhancement applied checks whether the statement to be replaced has any siblings or not. If no sibling is found, then the statement gets replaced with a "pass" statement instead of a blank line.
By doing this, Python source files generated by 2to3 are more readily runnable right after the transformation.
Morty Proxy This is a proxified and sanitized view of the page, visit original site.