Home | History | Annotate | Download | only in fixes
      1 # Copyright 2007 Google, Inc. All Rights Reserved.
      2 # Licensed to PSF under a Contributor Agreement.
      3 
      4 """Fixer that changes map(F, ...) into list(map(F, ...)) unless there
      5 exists a 'from future_builtins import map' statement in the top-level
      6 namespace.
      7 
      8 As a special case, map(None, X) is changed into list(X).  (This is
      9 necessary because the semantics are changed in this case -- the new
     10 map(None, X) is equivalent to [(x,) for x in X].)
     11 
     12 We avoid the transformation (except for the special case mentioned
     13 above) if the map() call is directly contained in iter(<>), list(<>),
     14 tuple(<>), sorted(<>), ...join(<>), or for V in <>:.
     15 
     16 NOTE: This is still not correct if the original code was depending on
     17 map(F, X, Y, ...) to go on until the longest argument is exhausted,
     18 substituting None for missing values -- like zip(), it now stops as
     19 soon as the shortest argument is exhausted.
     20 """
     21 
     22 # Local imports
     23 from ..pgen2 import token
     24 from .. import fixer_base
     25 from ..fixer_util import Name, Call, ListComp, in_special_context
     26 from ..pygram import python_symbols as syms
     27 
     28 class FixMap(fixer_base.ConditionalFix):
     29     BM_compatible = True
     30 
     31     PATTERN = """
     32     map_none=power<
     33         'map'
     34         trailer< '(' arglist< 'None' ',' arg=any [','] > ')' >
     35     >
     36     |
     37     map_lambda=power<
     38         'map'
     39         trailer<
     40             '('
     41             arglist<
     42                 lambdef< 'lambda'
     43                          (fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any
     44                 >
     45                 ','
     46                 it=any
     47             >
     48             ')'
     49         >
     50     >
     51     |
     52     power<
     53         'map' trailer< '(' [arglist=any] ')' >
     54     >
     55     """
     56 
     57     skip_on = 'future_builtins.map'
     58 
     59     def transform(self, node, results):
     60         if self.should_skip(node):
     61             return
     62 
     63         if node.parent.type == syms.simple_stmt:
     64             self.warning(node, "You should use a for loop here")
     65             new = node.clone()
     66             new.prefix = u""
     67             new = Call(Name(u"list"), [new])
     68         elif "map_lambda" in results:
     69             new = ListComp(results["xp"].clone(),
     70                            results["fp"].clone(),
     71                            results["it"].clone())
     72         else:
     73             if "map_none" in results:
     74                 new = results["arg"].clone()
     75             else:
     76                 if "arglist" in results:
     77                     args = results["arglist"]
     78                     if args.type == syms.arglist and \
     79                        args.children[0].type == token.NAME and \
     80                        args.children[0].value == "None":
     81                         self.warning(node, "cannot convert map(None, ...) "
     82                                      "with multiple arguments because map() "
     83                                      "now truncates to the shortest sequence")
     84                         return
     85                 if in_special_context(node):
     86                     return None
     87                 new = node.clone()
     88             new.prefix = u""
     89             new = Call(Name(u"list"), [new])
     90         new.prefix = node.prefix
     91         return new
     92