Skip to content

Commit a949bf4

Browse files
committed
Add fixer for itertools
Use of ifilter, imap, and izip as generator forms of PY2 builtins are replaced with future.builtins versions that are always generators
1 parent 7145e78 commit a949bf4

File tree

5 files changed

+137
-0
lines changed

5 files changed

+137
-0
lines changed

docs/futurize.rst

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ The complete set of fixers applied by ``futurize --stage1`` is:
103103
lib2to3.fixes.fix_ws_comma
104104
lib2to3.fixes.fix_xreadlines
105105
libfuturize.fixes.fix_absolute_import
106+
libfuturize.fixes.fix_itertools
106107
libfuturize.fixes.fix_next_call
107108
libfuturize.fixes.fix_print_with_import
108109
libfuturize.fixes.fix_raise

src/future/builtins/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
import builtins
1919
bytes = builtins.bytes
2020
dict = builtins.dict
21+
filter = builtins.filter
2122
int = builtins.int
2223
list = builtins.list
24+
map = builtins.map
2325
object = builtins.object
2426
range = builtins.range
2527
str = builtins.str
28+
zip = builtins.zip
2629
__all__ = []
2730
else:
2831
from future.types import (newbytes as bytes,
@@ -32,6 +35,9 @@
3235
newobject as object,
3336
newrange as range,
3437
newstr as str)
38+
from itertools import (ifilter as filter,
39+
imap as map,
40+
izip as zip)
3541
from future import utils
3642

3743

src/libfuturize/fixes/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969

7070
libfuturize_fix_names_stage1 = set([
7171
'libfuturize.fixes.fix_absolute_import',
72+
'libfuturize.fixes.fix_itertools',
7273
'libfuturize.fixes.fix_next_call', # obj.next() -> next(obj). Unlike
7374
# lib2to3.fixes.fix_next, doesn't change
7475
# the ``next`` method to ``__next__``.
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
For the ``future`` package.
3+
4+
Fixer for itertools methods that no longer deviate from builtins.
5+
6+
This applies to imap, izip, and ifilter
7+
8+
Adds this import line:
9+
10+
from builtins import filter, map, zip
11+
12+
at the top.
13+
"""
14+
15+
from lib2to3 import fixer_base
16+
17+
from libfuturize.fixer_util import touch_import_top
18+
19+
filter_expression = "name='ifilter'"
20+
map_expression = "name='imap'"
21+
zip_expression = "name='izip'"
22+
23+
class FixFilter(fixer_base.BaseFix):
24+
25+
PATTERN = """
26+
power<
27+
({0}) trailer< '(' args=[any] ')' >
28+
rest=any* >
29+
""".format(filter_expression)
30+
31+
def transform(self, node, results):
32+
touch_import_top(u'builtins', 'filter', node)
33+
34+
class FixMap(fixer_base.BaseFix):
35+
36+
PATTERN = """
37+
power<
38+
({0}) trailer< '(' args=[any] ')' >
39+
rest=any* >
40+
""".format(map_rexpression)
41+
42+
def transform(self, node, results):
43+
touch_import_top(u'builtins', 'map', node)
44+
45+
class FixZip(fixer_base.BaseFix):
46+
47+
PATTERN = """
48+
power<
49+
({0}) trailer< '(' args=[any] ')' >
50+
rest=any* >
51+
""".format(zip_expression)
52+
53+
def transform(self, node, results):
54+
touch_import_top(u'builtins', 'zip', node)

tests/test_future/test_futurize.py

+75
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,81 @@ def test_xrange(self):
453453
"""
454454
self.convert_check(before, after, ignore_imports=False)
455455

456+
def test_filter(self):
457+
"""
458+
Tests correct handling of itertools.ifilter
459+
"""
460+
before = """
461+
import itertools
462+
itertools.ifilter(lambda x: x%2, [1, 2, 3, 4])
463+
"""
464+
after = """
465+
from builtins import filter
466+
import itertools
467+
filter(lambda x: x%2, [1, 2, 3, 4])
468+
"""
469+
self.convert_check(before, after, ignore_imports=False)
470+
before = """
471+
from itertools import ifilter
472+
ifilter(lambda x: x%2, [1, 2, 3, 4])
473+
"""
474+
after = """
475+
from builtins import filter
476+
477+
filter(lambda x: x%2, [1, 2, 3, 4])
478+
"""
479+
self.convert_check(before, after, ignore_imports=False)
480+
481+
def test_map(self):
482+
"""
483+
Tests correct handling of itertools.imap
484+
"""
485+
before = """
486+
import itertools
487+
itertools.imap(pow, (2,3,10), (5,2,3))
488+
"""
489+
after = """
490+
from builtins import map
491+
import itertools
492+
map(pow, (2,3,10), (5,2,3))
493+
"""
494+
self.convert_check(before, after, ignore_imports=False)
495+
before = """
496+
from itertools import imap
497+
imap(pow, (2,3,10), (5,2,3))
498+
"""
499+
after = """
500+
from builtins import map
501+
502+
map(pow, (2,3,10), (5,2,3))
503+
"""
504+
self.convert_check(before, after, ignore_imports=False)
505+
506+
def test_zip(self):
507+
"""
508+
Tests correct handling of itertools.izip
509+
"""
510+
before = """
511+
import itertools
512+
itertools.izip('ABCD', 'xy')
513+
"""
514+
after = """
515+
from builtins import zip
516+
import itertools
517+
zip('ABCD', 'xy')
518+
"""
519+
self.convert_check(before, after, ignore_imports=False)
520+
before = """
521+
from itertools import izip
522+
izip('ABCD', 'xy')
523+
"""
524+
after = """
525+
from builtins import zip
526+
527+
zip('ABCD', 'xy')
528+
"""
529+
self.convert_check(before, after, ignore_imports=False)
530+
456531
def test_source_coding_utf8(self):
457532
"""
458533
Tests to ensure that the source coding line is not corrupted or

0 commit comments

Comments
 (0)