| # Copyright 2007 Google, Inc. All Rights Reserved. | |
| # Licensed to PSF under a Contributor Agreement. | |
| """Fixer that changes map(F, ...) into list(map(F, ...)) unless there | |
| exists a 'from future_builtins import map' statement in the top-level | |
| namespace. | |
| As a special case, map(None, X) is changed into list(X). (This is | |
| necessary because the semantics are changed in this case -- the new | |
| map(None, X) is equivalent to [(x,) for x in X].) | |
| We avoid the transformation (except for the special case mentioned | |
| above) if the map() call is directly contained in iter(<>), list(<>), | |
| tuple(<>), sorted(<>), ...join(<>), or for V in <>:. | |
| NOTE: This is still not correct if the original code was depending on | |
| map(F, X, Y, ...) to go on until the longest argument is exhausted, | |
| substituting None for missing values -- like zip(), it now stops as | |
| soon as the shortest argument is exhausted. | |
| """ | |
| # Local imports | |
| from ..pgen2 import token | |
| from .. import fixer_base | |
| from ..fixer_util import Name, Call, ListComp, in_special_context | |
| from ..pygram import python_symbols as syms | |
| class FixMap(fixer_base.ConditionalFix): | |
| BM_compatible = True | |
| PATTERN = """ | |
| map_none=power< | |
| 'map' | |
| trailer< '(' arglist< 'None' ',' arg=any [','] > ')' > | |
| > | |
| | | |
| map_lambda=power< | |
| 'map' | |
| trailer< | |
| '(' | |
| arglist< | |
| lambdef< 'lambda' | |
| (fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any | |
| > | |
| ',' | |
| it=any | |
| > | |
| ')' | |
| > | |
| > | |
| | | |
| power< | |
| 'map' trailer< '(' [arglist=any] ')' > | |
| > | |
| """ | |
| skip_on = 'future_builtins.map' | |
| def transform(self, node, results): | |
| if self.should_skip(node): | |
| return | |
| if node.parent.type == syms.simple_stmt: | |
| self.warning(node, "You should use a for loop here") | |
| new = node.clone() | |
| new.prefix = u"" | |
| new = Call(Name(u"list"), [new]) | |
| elif "map_lambda" in results: | |
| new = ListComp(results["xp"].clone(), | |
| results["fp"].clone(), | |
| results["it"].clone()) | |
| else: | |
| if "map_none" in results: | |
| new = results["arg"].clone() | |
| else: | |
| if "arglist" in results: | |
| args = results["arglist"] | |
| if args.type == syms.arglist and \ | |
| args.children[0].type == token.NAME and \ | |
| args.children[0].value == "None": | |
| self.warning(node, "cannot convert map(None, ...) " | |
| "with multiple arguments because map() " | |
| "now truncates to the shortest sequence") | |
| return | |
| if in_special_context(node): | |
| return None | |
| new = node.clone() | |
| new.prefix = u"" | |
| new = Call(Name(u"list"), [new]) | |
| new.prefix = node.prefix | |
| return new |