update windows build to Python 3.7
This commit is contained in:
parent
73105fa71e
commit
ddc59ab92d
5761 changed files with 750298 additions and 213405 deletions
154
Lib/lib2to3/Grammar.txt
Normal file
154
Lib/lib2to3/Grammar.txt
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# Grammar for 2to3. This grammar supports Python 2.x and 3.x.
|
||||
|
||||
# NOTE WELL: You should also follow all the steps listed at
|
||||
# https://devguide.python.org/grammar/
|
||||
|
||||
# Start symbols for the grammar:
|
||||
# file_input is a module or sequence of commands read from an input file;
|
||||
# single_input is a single interactive statement;
|
||||
# eval_input is the input for the eval() and input() functions.
|
||||
# NB: compound_stmt in single_input is followed by extra NEWLINE!
|
||||
file_input: (NEWLINE | stmt)* ENDMARKER
|
||||
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
|
||||
eval_input: testlist NEWLINE* ENDMARKER
|
||||
|
||||
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
|
||||
decorators: decorator+
|
||||
decorated: decorators (classdef | funcdef | async_funcdef)
|
||||
async_funcdef: ASYNC funcdef
|
||||
funcdef: 'def' NAME parameters ['->' test] ':' suite
|
||||
parameters: '(' [typedargslist] ')'
|
||||
typedargslist: ((tfpdef ['=' test] ',')*
|
||||
('*' [tname] (',' tname ['=' test])* [',' ['**' tname [',']]] | '**' tname [','])
|
||||
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
|
||||
tname: NAME [':' test]
|
||||
tfpdef: tname | '(' tfplist ')'
|
||||
tfplist: tfpdef (',' tfpdef)* [',']
|
||||
varargslist: ((vfpdef ['=' test] ',')*
|
||||
('*' [vname] (',' vname ['=' test])* [',' ['**' vname [',']]] | '**' vname [','])
|
||||
| vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
|
||||
vname: NAME
|
||||
vfpdef: vname | '(' vfplist ')'
|
||||
vfplist: vfpdef (',' vfpdef)* [',']
|
||||
|
||||
stmt: simple_stmt | compound_stmt
|
||||
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
|
||||
small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt |
|
||||
import_stmt | global_stmt | exec_stmt | assert_stmt)
|
||||
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
|
||||
('=' (yield_expr|testlist_star_expr))*)
|
||||
annassign: ':' test ['=' test]
|
||||
testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
|
||||
augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
|
||||
'<<=' | '>>=' | '**=' | '//=')
|
||||
# For normal and annotated assignments, additional restrictions enforced by the interpreter
|
||||
print_stmt: 'print' ( [ test (',' test)* [','] ] |
|
||||
'>>' test [ (',' test)+ [','] ] )
|
||||
del_stmt: 'del' exprlist
|
||||
pass_stmt: 'pass'
|
||||
flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
|
||||
break_stmt: 'break'
|
||||
continue_stmt: 'continue'
|
||||
return_stmt: 'return' [testlist]
|
||||
yield_stmt: yield_expr
|
||||
raise_stmt: 'raise' [test ['from' test | ',' test [',' test]]]
|
||||
import_stmt: import_name | import_from
|
||||
import_name: 'import' dotted_as_names
|
||||
import_from: ('from' ('.'* dotted_name | '.'+)
|
||||
'import' ('*' | '(' import_as_names ')' | import_as_names))
|
||||
import_as_name: NAME ['as' NAME]
|
||||
dotted_as_name: dotted_name ['as' NAME]
|
||||
import_as_names: import_as_name (',' import_as_name)* [',']
|
||||
dotted_as_names: dotted_as_name (',' dotted_as_name)*
|
||||
dotted_name: NAME ('.' NAME)*
|
||||
global_stmt: ('global' | 'nonlocal') NAME (',' NAME)*
|
||||
exec_stmt: 'exec' expr ['in' test [',' test]]
|
||||
assert_stmt: 'assert' test [',' test]
|
||||
|
||||
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
|
||||
async_stmt: ASYNC (funcdef | with_stmt | for_stmt)
|
||||
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
|
||||
while_stmt: 'while' test ':' suite ['else' ':' suite]
|
||||
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
|
||||
try_stmt: ('try' ':' suite
|
||||
((except_clause ':' suite)+
|
||||
['else' ':' suite]
|
||||
['finally' ':' suite] |
|
||||
'finally' ':' suite))
|
||||
with_stmt: 'with' with_item (',' with_item)* ':' suite
|
||||
with_item: test ['as' expr]
|
||||
with_var: 'as' expr
|
||||
# NB compile.c makes sure that the default except clause is last
|
||||
except_clause: 'except' [test [(',' | 'as') test]]
|
||||
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
|
||||
|
||||
# Backward compatibility cruft to support:
|
||||
# [ x for x in lambda: True, lambda: False if x() ]
|
||||
# even while also allowing:
|
||||
# lambda x: 5 if x else 2
|
||||
# (But not a mix of the two)
|
||||
testlist_safe: old_test [(',' old_test)+ [',']]
|
||||
old_test: or_test | old_lambdef
|
||||
old_lambdef: 'lambda' [varargslist] ':' old_test
|
||||
|
||||
test: or_test ['if' or_test 'else' test] | lambdef
|
||||
or_test: and_test ('or' and_test)*
|
||||
and_test: not_test ('and' not_test)*
|
||||
not_test: 'not' not_test | comparison
|
||||
comparison: expr (comp_op expr)*
|
||||
comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
|
||||
star_expr: '*' expr
|
||||
expr: xor_expr ('|' xor_expr)*
|
||||
xor_expr: and_expr ('^' and_expr)*
|
||||
and_expr: shift_expr ('&' shift_expr)*
|
||||
shift_expr: arith_expr (('<<'|'>>') arith_expr)*
|
||||
arith_expr: term (('+'|'-') term)*
|
||||
term: factor (('*'|'@'|'/'|'%'|'//') factor)*
|
||||
factor: ('+'|'-'|'~') factor | power
|
||||
power: [AWAIT] atom trailer* ['**' factor]
|
||||
atom: ('(' [yield_expr|testlist_gexp] ')' |
|
||||
'[' [listmaker] ']' |
|
||||
'{' [dictsetmaker] '}' |
|
||||
'`' testlist1 '`' |
|
||||
NAME | NUMBER | STRING+ | '.' '.' '.')
|
||||
listmaker: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
|
||||
testlist_gexp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
|
||||
lambdef: 'lambda' [varargslist] ':' test
|
||||
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
|
||||
subscriptlist: subscript (',' subscript)* [',']
|
||||
subscript: test | [test] ':' [test] [sliceop]
|
||||
sliceop: ':' [test]
|
||||
exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']
|
||||
testlist: test (',' test)* [',']
|
||||
dictsetmaker: ( ((test ':' test | '**' expr)
|
||||
(comp_for | (',' (test ':' test | '**' expr))* [','])) |
|
||||
((test | star_expr)
|
||||
(comp_for | (',' (test | star_expr))* [','])) )
|
||||
|
||||
classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
|
||||
|
||||
arglist: argument (',' argument)* [',']
|
||||
|
||||
# "test '=' test" is really "keyword '=' test", but we have no such token.
|
||||
# These need to be in a single rule to avoid grammar that is ambiguous
|
||||
# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr,
|
||||
# we explicitly match '*' here, too, to give it proper precedence.
|
||||
# Illegal combinations and orderings are blocked in ast.c:
|
||||
# multiple (test comp_for) arguments are blocked; keyword unpackings
|
||||
# that precede iterable unpackings are blocked; etc.
|
||||
argument: ( test [comp_for] |
|
||||
test '=' test |
|
||||
'**' expr |
|
||||
star_expr )
|
||||
|
||||
comp_iter: comp_for | comp_if
|
||||
comp_for: [ASYNC] 'for' exprlist 'in' testlist_safe [comp_iter]
|
||||
comp_if: 'if' old_test [comp_iter]
|
||||
|
||||
testlist1: test (',' test)*
|
||||
|
||||
# not used in grammar, but may appear in "node" passed from Parser to Compiler
|
||||
encoding_decl: NAME
|
||||
|
||||
yield_expr: 'yield' [yield_arg]
|
||||
yield_arg: 'from' test | testlist
|
||||
BIN
Lib/lib2to3/Grammar3.7.2.final.0.pickle
Normal file
BIN
Lib/lib2to3/Grammar3.7.2.final.0.pickle
Normal file
Binary file not shown.
28
Lib/lib2to3/PatternGrammar.txt
Normal file
28
Lib/lib2to3/PatternGrammar.txt
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
# A grammar to describe tree matching patterns.
|
||||
# Not shown here:
|
||||
# - 'TOKEN' stands for any token (leaf node)
|
||||
# - 'any' stands for any node (leaf or interior)
|
||||
# With 'any' we can still specify the sub-structure.
|
||||
|
||||
# The start symbol is 'Matcher'.
|
||||
|
||||
Matcher: Alternatives ENDMARKER
|
||||
|
||||
Alternatives: Alternative ('|' Alternative)*
|
||||
|
||||
Alternative: (Unit | NegatedUnit)+
|
||||
|
||||
Unit: [NAME '='] ( STRING [Repeater]
|
||||
| NAME [Details] [Repeater]
|
||||
| '(' Alternatives ')' [Repeater]
|
||||
| '[' Alternatives ']'
|
||||
)
|
||||
|
||||
NegatedUnit: 'not' (STRING | NAME [Details] | '(' Alternatives ')')
|
||||
|
||||
Repeater: '*' | '+' | '{' NUMBER [',' NUMBER] '}'
|
||||
|
||||
Details: '<' Alternatives '>'
|
||||
BIN
Lib/lib2to3/PatternGrammar3.7.2.final.0.pickle
Normal file
BIN
Lib/lib2to3/PatternGrammar3.7.2.final.0.pickle
Normal file
Binary file not shown.
1
Lib/lib2to3/__init__.py
Normal file
1
Lib/lib2to3/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
#empty
|
||||
4
Lib/lib2to3/__main__.py
Normal file
4
Lib/lib2to3/__main__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import sys
|
||||
from .main import main
|
||||
|
||||
sys.exit(main("lib2to3.fixes"))
|
||||
BIN
Lib/lib2to3/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/btm_matcher.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/btm_matcher.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/btm_utils.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/btm_utils.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/fixer_base.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/fixer_base.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/fixer_util.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/fixer_util.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/patcomp.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/patcomp.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/pygram.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/pygram.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/pytree.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/pytree.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/__pycache__/refactor.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/__pycache__/refactor.cpython-37.pyc
Normal file
Binary file not shown.
163
Lib/lib2to3/btm_matcher.py
Normal file
163
Lib/lib2to3/btm_matcher.py
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
"""A bottom-up tree matching algorithm implementation meant to speed
|
||||
up 2to3's matching process. After the tree patterns are reduced to
|
||||
their rarest linear path, a linear Aho-Corasick automaton is
|
||||
created. The linear automaton traverses the linear paths from the
|
||||
leaves to the root of the AST and returns a set of nodes for further
|
||||
matching. This reduces significantly the number of candidate nodes."""
|
||||
|
||||
__author__ = "George Boutsioukis <gboutsioukis@gmail.com>"
|
||||
|
||||
import logging
|
||||
import itertools
|
||||
from collections import defaultdict
|
||||
|
||||
from . import pytree
|
||||
from .btm_utils import reduce_tree
|
||||
|
||||
class BMNode(object):
|
||||
"""Class for a node of the Aho-Corasick automaton used in matching"""
|
||||
count = itertools.count()
|
||||
def __init__(self):
|
||||
self.transition_table = {}
|
||||
self.fixers = []
|
||||
self.id = next(BMNode.count)
|
||||
self.content = ''
|
||||
|
||||
class BottomMatcher(object):
|
||||
"""The main matcher class. After instantiating the patterns should
|
||||
be added using the add_fixer method"""
|
||||
|
||||
def __init__(self):
|
||||
self.match = set()
|
||||
self.root = BMNode()
|
||||
self.nodes = [self.root]
|
||||
self.fixers = []
|
||||
self.logger = logging.getLogger("RefactoringTool")
|
||||
|
||||
def add_fixer(self, fixer):
|
||||
"""Reduces a fixer's pattern tree to a linear path and adds it
|
||||
to the matcher(a common Aho-Corasick automaton). The fixer is
|
||||
appended on the matching states and called when they are
|
||||
reached"""
|
||||
self.fixers.append(fixer)
|
||||
tree = reduce_tree(fixer.pattern_tree)
|
||||
linear = tree.get_linear_subpattern()
|
||||
match_nodes = self.add(linear, start=self.root)
|
||||
for match_node in match_nodes:
|
||||
match_node.fixers.append(fixer)
|
||||
|
||||
def add(self, pattern, start):
|
||||
"Recursively adds a linear pattern to the AC automaton"
|
||||
#print("adding pattern", pattern, "to", start)
|
||||
if not pattern:
|
||||
#print("empty pattern")
|
||||
return [start]
|
||||
if isinstance(pattern[0], tuple):
|
||||
#alternatives
|
||||
#print("alternatives")
|
||||
match_nodes = []
|
||||
for alternative in pattern[0]:
|
||||
#add all alternatives, and add the rest of the pattern
|
||||
#to each end node
|
||||
end_nodes = self.add(alternative, start=start)
|
||||
for end in end_nodes:
|
||||
match_nodes.extend(self.add(pattern[1:], end))
|
||||
return match_nodes
|
||||
else:
|
||||
#single token
|
||||
#not last
|
||||
if pattern[0] not in start.transition_table:
|
||||
#transition did not exist, create new
|
||||
next_node = BMNode()
|
||||
start.transition_table[pattern[0]] = next_node
|
||||
else:
|
||||
#transition exists already, follow
|
||||
next_node = start.transition_table[pattern[0]]
|
||||
|
||||
if pattern[1:]:
|
||||
end_nodes = self.add(pattern[1:], start=next_node)
|
||||
else:
|
||||
end_nodes = [next_node]
|
||||
return end_nodes
|
||||
|
||||
def run(self, leaves):
|
||||
"""The main interface with the bottom matcher. The tree is
|
||||
traversed from the bottom using the constructed
|
||||
automaton. Nodes are only checked once as the tree is
|
||||
retraversed. When the automaton fails, we give it one more
|
||||
shot(in case the above tree matches as a whole with the
|
||||
rejected leaf), then we break for the next leaf. There is the
|
||||
special case of multiple arguments(see code comments) where we
|
||||
recheck the nodes
|
||||
|
||||
Args:
|
||||
The leaves of the AST tree to be matched
|
||||
|
||||
Returns:
|
||||
A dictionary of node matches with fixers as the keys
|
||||
"""
|
||||
current_ac_node = self.root
|
||||
results = defaultdict(list)
|
||||
for leaf in leaves:
|
||||
current_ast_node = leaf
|
||||
while current_ast_node:
|
||||
current_ast_node.was_checked = True
|
||||
for child in current_ast_node.children:
|
||||
# multiple statements, recheck
|
||||
if isinstance(child, pytree.Leaf) and child.value == ";":
|
||||
current_ast_node.was_checked = False
|
||||
break
|
||||
if current_ast_node.type == 1:
|
||||
#name
|
||||
node_token = current_ast_node.value
|
||||
else:
|
||||
node_token = current_ast_node.type
|
||||
|
||||
if node_token in current_ac_node.transition_table:
|
||||
#token matches
|
||||
current_ac_node = current_ac_node.transition_table[node_token]
|
||||
for fixer in current_ac_node.fixers:
|
||||
results[fixer].append(current_ast_node)
|
||||
else:
|
||||
#matching failed, reset automaton
|
||||
current_ac_node = self.root
|
||||
if (current_ast_node.parent is not None
|
||||
and current_ast_node.parent.was_checked):
|
||||
#the rest of the tree upwards has been checked, next leaf
|
||||
break
|
||||
|
||||
#recheck the rejected node once from the root
|
||||
if node_token in current_ac_node.transition_table:
|
||||
#token matches
|
||||
current_ac_node = current_ac_node.transition_table[node_token]
|
||||
for fixer in current_ac_node.fixers:
|
||||
results[fixer].append(current_ast_node)
|
||||
|
||||
current_ast_node = current_ast_node.parent
|
||||
return results
|
||||
|
||||
def print_ac(self):
|
||||
"Prints a graphviz diagram of the BM automaton(for debugging)"
|
||||
print("digraph g{")
|
||||
def print_node(node):
|
||||
for subnode_key in node.transition_table.keys():
|
||||
subnode = node.transition_table[subnode_key]
|
||||
print("%d -> %d [label=%s] //%s" %
|
||||
(node.id, subnode.id, type_repr(subnode_key), str(subnode.fixers)))
|
||||
if subnode_key == 1:
|
||||
print(subnode.content)
|
||||
print_node(subnode)
|
||||
print_node(self.root)
|
||||
print("}")
|
||||
|
||||
# taken from pytree.py for debugging; only used by print_ac
|
||||
_type_reprs = {}
|
||||
def type_repr(type_num):
|
||||
global _type_reprs
|
||||
if not _type_reprs:
|
||||
from .pygram import python_symbols
|
||||
# printing tokens is possible but not as useful
|
||||
# from .pgen2 import token // token.__dict__.items():
|
||||
for name, val in python_symbols.__dict__.items():
|
||||
if type(val) == int: _type_reprs[val] = name
|
||||
return _type_reprs.setdefault(type_num, type_num)
|
||||
281
Lib/lib2to3/btm_utils.py
Normal file
281
Lib/lib2to3/btm_utils.py
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
"Utility functions used by the btm_matcher module"
|
||||
|
||||
from . import pytree
|
||||
from .pgen2 import grammar, token
|
||||
from .pygram import pattern_symbols, python_symbols
|
||||
|
||||
syms = pattern_symbols
|
||||
pysyms = python_symbols
|
||||
tokens = grammar.opmap
|
||||
token_labels = token
|
||||
|
||||
TYPE_ANY = -1
|
||||
TYPE_ALTERNATIVES = -2
|
||||
TYPE_GROUP = -3
|
||||
|
||||
class MinNode(object):
|
||||
"""This class serves as an intermediate representation of the
|
||||
pattern tree during the conversion to sets of leaf-to-root
|
||||
subpatterns"""
|
||||
|
||||
def __init__(self, type=None, name=None):
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.children = []
|
||||
self.leaf = False
|
||||
self.parent = None
|
||||
self.alternatives = []
|
||||
self.group = []
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.type) + ' ' + str(self.name)
|
||||
|
||||
def leaf_to_root(self):
|
||||
"""Internal method. Returns a characteristic path of the
|
||||
pattern tree. This method must be run for all leaves until the
|
||||
linear subpatterns are merged into a single"""
|
||||
node = self
|
||||
subp = []
|
||||
while node:
|
||||
if node.type == TYPE_ALTERNATIVES:
|
||||
node.alternatives.append(subp)
|
||||
if len(node.alternatives) == len(node.children):
|
||||
#last alternative
|
||||
subp = [tuple(node.alternatives)]
|
||||
node.alternatives = []
|
||||
node = node.parent
|
||||
continue
|
||||
else:
|
||||
node = node.parent
|
||||
subp = None
|
||||
break
|
||||
|
||||
if node.type == TYPE_GROUP:
|
||||
node.group.append(subp)
|
||||
#probably should check the number of leaves
|
||||
if len(node.group) == len(node.children):
|
||||
subp = get_characteristic_subpattern(node.group)
|
||||
node.group = []
|
||||
node = node.parent
|
||||
continue
|
||||
else:
|
||||
node = node.parent
|
||||
subp = None
|
||||
break
|
||||
|
||||
if node.type == token_labels.NAME and node.name:
|
||||
#in case of type=name, use the name instead
|
||||
subp.append(node.name)
|
||||
else:
|
||||
subp.append(node.type)
|
||||
|
||||
node = node.parent
|
||||
return subp
|
||||
|
||||
def get_linear_subpattern(self):
|
||||
"""Drives the leaf_to_root method. The reason that
|
||||
leaf_to_root must be run multiple times is because we need to
|
||||
reject 'group' matches; for example the alternative form
|
||||
(a | b c) creates a group [b c] that needs to be matched. Since
|
||||
matching multiple linear patterns overcomes the automaton's
|
||||
capabilities, leaf_to_root merges each group into a single
|
||||
choice based on 'characteristic'ity,
|
||||
|
||||
i.e. (a|b c) -> (a|b) if b more characteristic than c
|
||||
|
||||
Returns: The most 'characteristic'(as defined by
|
||||
get_characteristic_subpattern) path for the compiled pattern
|
||||
tree.
|
||||
"""
|
||||
|
||||
for l in self.leaves():
|
||||
subp = l.leaf_to_root()
|
||||
if subp:
|
||||
return subp
|
||||
|
||||
def leaves(self):
|
||||
"Generator that returns the leaves of the tree"
|
||||
for child in self.children:
|
||||
yield from child.leaves()
|
||||
if not self.children:
|
||||
yield self
|
||||
|
||||
def reduce_tree(node, parent=None):
|
||||
"""
|
||||
Internal function. Reduces a compiled pattern tree to an
|
||||
intermediate representation suitable for feeding the
|
||||
automaton. This also trims off any optional pattern elements(like
|
||||
[a], a*).
|
||||
"""
|
||||
|
||||
new_node = None
|
||||
#switch on the node type
|
||||
if node.type == syms.Matcher:
|
||||
#skip
|
||||
node = node.children[0]
|
||||
|
||||
if node.type == syms.Alternatives :
|
||||
#2 cases
|
||||
if len(node.children) <= 2:
|
||||
#just a single 'Alternative', skip this node
|
||||
new_node = reduce_tree(node.children[0], parent)
|
||||
else:
|
||||
#real alternatives
|
||||
new_node = MinNode(type=TYPE_ALTERNATIVES)
|
||||
#skip odd children('|' tokens)
|
||||
for child in node.children:
|
||||
if node.children.index(child)%2:
|
||||
continue
|
||||
reduced = reduce_tree(child, new_node)
|
||||
if reduced is not None:
|
||||
new_node.children.append(reduced)
|
||||
elif node.type == syms.Alternative:
|
||||
if len(node.children) > 1:
|
||||
|
||||
new_node = MinNode(type=TYPE_GROUP)
|
||||
for child in node.children:
|
||||
reduced = reduce_tree(child, new_node)
|
||||
if reduced:
|
||||
new_node.children.append(reduced)
|
||||
if not new_node.children:
|
||||
# delete the group if all of the children were reduced to None
|
||||
new_node = None
|
||||
|
||||
else:
|
||||
new_node = reduce_tree(node.children[0], parent)
|
||||
|
||||
elif node.type == syms.Unit:
|
||||
if (isinstance(node.children[0], pytree.Leaf) and
|
||||
node.children[0].value == '('):
|
||||
#skip parentheses
|
||||
return reduce_tree(node.children[1], parent)
|
||||
if ((isinstance(node.children[0], pytree.Leaf) and
|
||||
node.children[0].value == '[')
|
||||
or
|
||||
(len(node.children)>1 and
|
||||
hasattr(node.children[1], "value") and
|
||||
node.children[1].value == '[')):
|
||||
#skip whole unit if its optional
|
||||
return None
|
||||
|
||||
leaf = True
|
||||
details_node = None
|
||||
alternatives_node = None
|
||||
has_repeater = False
|
||||
repeater_node = None
|
||||
has_variable_name = False
|
||||
|
||||
for child in node.children:
|
||||
if child.type == syms.Details:
|
||||
leaf = False
|
||||
details_node = child
|
||||
elif child.type == syms.Repeater:
|
||||
has_repeater = True
|
||||
repeater_node = child
|
||||
elif child.type == syms.Alternatives:
|
||||
alternatives_node = child
|
||||
if hasattr(child, 'value') and child.value == '=': # variable name
|
||||
has_variable_name = True
|
||||
|
||||
#skip variable name
|
||||
if has_variable_name:
|
||||
#skip variable name, '='
|
||||
name_leaf = node.children[2]
|
||||
if hasattr(name_leaf, 'value') and name_leaf.value == '(':
|
||||
# skip parenthesis
|
||||
name_leaf = node.children[3]
|
||||
else:
|
||||
name_leaf = node.children[0]
|
||||
|
||||
#set node type
|
||||
if name_leaf.type == token_labels.NAME:
|
||||
#(python) non-name or wildcard
|
||||
if name_leaf.value == 'any':
|
||||
new_node = MinNode(type=TYPE_ANY)
|
||||
else:
|
||||
if hasattr(token_labels, name_leaf.value):
|
||||
new_node = MinNode(type=getattr(token_labels, name_leaf.value))
|
||||
else:
|
||||
new_node = MinNode(type=getattr(pysyms, name_leaf.value))
|
||||
|
||||
elif name_leaf.type == token_labels.STRING:
|
||||
#(python) name or character; remove the apostrophes from
|
||||
#the string value
|
||||
name = name_leaf.value.strip("'")
|
||||
if name in tokens:
|
||||
new_node = MinNode(type=tokens[name])
|
||||
else:
|
||||
new_node = MinNode(type=token_labels.NAME, name=name)
|
||||
elif name_leaf.type == syms.Alternatives:
|
||||
new_node = reduce_tree(alternatives_node, parent)
|
||||
|
||||
#handle repeaters
|
||||
if has_repeater:
|
||||
if repeater_node.children[0].value == '*':
|
||||
#reduce to None
|
||||
new_node = None
|
||||
elif repeater_node.children[0].value == '+':
|
||||
#reduce to a single occurrence i.e. do nothing
|
||||
pass
|
||||
else:
|
||||
#TODO: handle {min, max} repeaters
|
||||
raise NotImplementedError
|
||||
pass
|
||||
|
||||
#add children
|
||||
if details_node and new_node is not None:
|
||||
for child in details_node.children[1:-1]:
|
||||
#skip '<', '>' markers
|
||||
reduced = reduce_tree(child, new_node)
|
||||
if reduced is not None:
|
||||
new_node.children.append(reduced)
|
||||
if new_node:
|
||||
new_node.parent = parent
|
||||
return new_node
|
||||
|
||||
|
||||
def get_characteristic_subpattern(subpatterns):
|
||||
"""Picks the most characteristic from a list of linear patterns
|
||||
Current order used is:
|
||||
names > common_names > common_chars
|
||||
"""
|
||||
if not isinstance(subpatterns, list):
|
||||
return subpatterns
|
||||
if len(subpatterns)==1:
|
||||
return subpatterns[0]
|
||||
|
||||
# first pick out the ones containing variable names
|
||||
subpatterns_with_names = []
|
||||
subpatterns_with_common_names = []
|
||||
common_names = ['in', 'for', 'if' , 'not', 'None']
|
||||
subpatterns_with_common_chars = []
|
||||
common_chars = "[]().,:"
|
||||
for subpattern in subpatterns:
|
||||
if any(rec_test(subpattern, lambda x: type(x) is str)):
|
||||
if any(rec_test(subpattern,
|
||||
lambda x: isinstance(x, str) and x in common_chars)):
|
||||
subpatterns_with_common_chars.append(subpattern)
|
||||
elif any(rec_test(subpattern,
|
||||
lambda x: isinstance(x, str) and x in common_names)):
|
||||
subpatterns_with_common_names.append(subpattern)
|
||||
|
||||
else:
|
||||
subpatterns_with_names.append(subpattern)
|
||||
|
||||
if subpatterns_with_names:
|
||||
subpatterns = subpatterns_with_names
|
||||
elif subpatterns_with_common_names:
|
||||
subpatterns = subpatterns_with_common_names
|
||||
elif subpatterns_with_common_chars:
|
||||
subpatterns = subpatterns_with_common_chars
|
||||
# of the remaining subpatterns pick out the longest one
|
||||
return max(subpatterns, key=len)
|
||||
|
||||
def rec_test(sequence, test_func):
|
||||
"""Tests test_func on all items of sequence and items of included
|
||||
sub-iterables"""
|
||||
for x in sequence:
|
||||
if isinstance(x, (list, tuple)):
|
||||
yield from rec_test(x, test_func)
|
||||
else:
|
||||
yield test_func(x)
|
||||
186
Lib/lib2to3/fixer_base.py
Normal file
186
Lib/lib2to3/fixer_base.py
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Base class for fixers (optional, but recommended)."""
|
||||
|
||||
# Python imports
|
||||
import itertools
|
||||
|
||||
# Local imports
|
||||
from .patcomp import PatternCompiler
|
||||
from . import pygram
|
||||
from .fixer_util import does_tree_import
|
||||
|
||||
class BaseFix(object):
|
||||
|
||||
"""Optional base class for fixers.
|
||||
|
||||
The subclass name must be FixFooBar where FooBar is the result of
|
||||
removing underscores and capitalizing the words of the fix name.
|
||||
For example, the class name for a fixer named 'has_key' should be
|
||||
FixHasKey.
|
||||
"""
|
||||
|
||||
PATTERN = None # Most subclasses should override with a string literal
|
||||
pattern = None # Compiled pattern, set by compile_pattern()
|
||||
pattern_tree = None # Tree representation of the pattern
|
||||
options = None # Options object passed to initializer
|
||||
filename = None # The filename (set by set_filename)
|
||||
numbers = itertools.count(1) # For new_name()
|
||||
used_names = set() # A set of all used NAMEs
|
||||
order = "post" # Does the fixer prefer pre- or post-order traversal
|
||||
explicit = False # Is this ignored by refactor.py -f all?
|
||||
run_order = 5 # Fixers will be sorted by run order before execution
|
||||
# Lower numbers will be run first.
|
||||
_accept_type = None # [Advanced and not public] This tells RefactoringTool
|
||||
# which node type to accept when there's not a pattern.
|
||||
|
||||
keep_line_order = False # For the bottom matcher: match with the
|
||||
# original line order
|
||||
BM_compatible = False # Compatibility with the bottom matching
|
||||
# module; every fixer should set this
|
||||
# manually
|
||||
|
||||
# Shortcut for access to Python grammar symbols
|
||||
syms = pygram.python_symbols
|
||||
|
||||
def __init__(self, options, log):
|
||||
"""Initializer. Subclass may override.
|
||||
|
||||
Args:
|
||||
options: a dict containing the options passed to RefactoringTool
|
||||
that could be used to customize the fixer through the command line.
|
||||
log: a list to append warnings and other messages to.
|
||||
"""
|
||||
self.options = options
|
||||
self.log = log
|
||||
self.compile_pattern()
|
||||
|
||||
def compile_pattern(self):
|
||||
"""Compiles self.PATTERN into self.pattern.
|
||||
|
||||
Subclass may override if it doesn't want to use
|
||||
self.{pattern,PATTERN} in .match().
|
||||
"""
|
||||
if self.PATTERN is not None:
|
||||
PC = PatternCompiler()
|
||||
self.pattern, self.pattern_tree = PC.compile_pattern(self.PATTERN,
|
||||
with_tree=True)
|
||||
|
||||
def set_filename(self, filename):
|
||||
"""Set the filename.
|
||||
|
||||
The main refactoring tool should call this.
|
||||
"""
|
||||
self.filename = filename
|
||||
|
||||
def match(self, node):
|
||||
"""Returns match for a given parse tree node.
|
||||
|
||||
Should return a true or false object (not necessarily a bool).
|
||||
It may return a non-empty dict of matching sub-nodes as
|
||||
returned by a matching pattern.
|
||||
|
||||
Subclass may override.
|
||||
"""
|
||||
results = {"node": node}
|
||||
return self.pattern.match(node, results) and results
|
||||
|
||||
def transform(self, node, results):
|
||||
"""Returns the transformation for a given parse tree node.
|
||||
|
||||
Args:
|
||||
node: the root of the parse tree that matched the fixer.
|
||||
results: a dict mapping symbolic names to part of the match.
|
||||
|
||||
Returns:
|
||||
None, or a node that is a modified copy of the
|
||||
argument node. The node argument may also be modified in-place to
|
||||
effect the same change.
|
||||
|
||||
Subclass *must* override.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def new_name(self, template="xxx_todo_changeme"):
|
||||
"""Return a string suitable for use as an identifier
|
||||
|
||||
The new name is guaranteed not to conflict with other identifiers.
|
||||
"""
|
||||
name = template
|
||||
while name in self.used_names:
|
||||
name = template + str(next(self.numbers))
|
||||
self.used_names.add(name)
|
||||
return name
|
||||
|
||||
def log_message(self, message):
|
||||
if self.first_log:
|
||||
self.first_log = False
|
||||
self.log.append("### In file %s ###" % self.filename)
|
||||
self.log.append(message)
|
||||
|
||||
def cannot_convert(self, node, reason=None):
|
||||
"""Warn the user that a given chunk of code is not valid Python 3,
|
||||
but that it cannot be converted automatically.
|
||||
|
||||
First argument is the top-level node for the code in question.
|
||||
Optional second argument is why it can't be converted.
|
||||
"""
|
||||
lineno = node.get_lineno()
|
||||
for_output = node.clone()
|
||||
for_output.prefix = ""
|
||||
msg = "Line %d: could not convert: %s"
|
||||
self.log_message(msg % (lineno, for_output))
|
||||
if reason:
|
||||
self.log_message(reason)
|
||||
|
||||
def warning(self, node, reason):
|
||||
"""Used for warning the user about possible uncertainty in the
|
||||
translation.
|
||||
|
||||
First argument is the top-level node for the code in question.
|
||||
Optional second argument is why it can't be converted.
|
||||
"""
|
||||
lineno = node.get_lineno()
|
||||
self.log_message("Line %d: %s" % (lineno, reason))
|
||||
|
||||
def start_tree(self, tree, filename):
|
||||
"""Some fixers need to maintain tree-wide state.
|
||||
This method is called once, at the start of tree fix-up.
|
||||
|
||||
tree - the root node of the tree to be processed.
|
||||
filename - the name of the file the tree came from.
|
||||
"""
|
||||
self.used_names = tree.used_names
|
||||
self.set_filename(filename)
|
||||
self.numbers = itertools.count(1)
|
||||
self.first_log = True
|
||||
|
||||
def finish_tree(self, tree, filename):
|
||||
"""Some fixers need to maintain tree-wide state.
|
||||
This method is called once, at the conclusion of tree fix-up.
|
||||
|
||||
tree - the root node of the tree to be processed.
|
||||
filename - the name of the file the tree came from.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ConditionalFix(BaseFix):
|
||||
""" Base class for fixers which not execute if an import is found. """
|
||||
|
||||
# This is the name of the import which, if found, will cause the test to be skipped
|
||||
skip_on = None
|
||||
|
||||
def start_tree(self, *args):
|
||||
super(ConditionalFix, self).start_tree(*args)
|
||||
self._should_skip = None
|
||||
|
||||
def should_skip(self, node):
|
||||
if self._should_skip is not None:
|
||||
return self._should_skip
|
||||
pkg = self.skip_on.split(".")
|
||||
name = pkg[-1]
|
||||
pkg = ".".join(pkg[:-1])
|
||||
self._should_skip = does_tree_import(pkg, name, node)
|
||||
return self._should_skip
|
||||
453
Lib/lib2to3/fixer_util.py
Normal file
453
Lib/lib2to3/fixer_util.py
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
"""Utility functions, node construction macros, etc."""
|
||||
# Author: Collin Winter
|
||||
|
||||
# Local imports
|
||||
from .pgen2 import token
|
||||
from .pytree import Leaf, Node
|
||||
from .pygram import python_symbols as syms
|
||||
from . import patcomp
|
||||
|
||||
|
||||
###########################################################
|
||||
### Common node-construction "macros"
|
||||
###########################################################
|
||||
|
||||
def KeywordArg(keyword, value):
|
||||
return Node(syms.argument,
|
||||
[keyword, Leaf(token.EQUAL, "="), value])
|
||||
|
||||
def LParen():
|
||||
return Leaf(token.LPAR, "(")
|
||||
|
||||
def RParen():
|
||||
return Leaf(token.RPAR, ")")
|
||||
|
||||
def Assign(target, source):
|
||||
"""Build an assignment statement"""
|
||||
if not isinstance(target, list):
|
||||
target = [target]
|
||||
if not isinstance(source, list):
|
||||
source.prefix = " "
|
||||
source = [source]
|
||||
|
||||
return Node(syms.atom,
|
||||
target + [Leaf(token.EQUAL, "=", prefix=" ")] + source)
|
||||
|
||||
def Name(name, prefix=None):
|
||||
"""Return a NAME leaf"""
|
||||
return Leaf(token.NAME, name, prefix=prefix)
|
||||
|
||||
def Attr(obj, attr):
|
||||
"""A node tuple for obj.attr"""
|
||||
return [obj, Node(syms.trailer, [Dot(), attr])]
|
||||
|
||||
def Comma():
|
||||
"""A comma leaf"""
|
||||
return Leaf(token.COMMA, ",")
|
||||
|
||||
def Dot():
|
||||
"""A period (.) leaf"""
|
||||
return Leaf(token.DOT, ".")
|
||||
|
||||
def ArgList(args, lparen=LParen(), rparen=RParen()):
|
||||
"""A parenthesised argument list, used by Call()"""
|
||||
node = Node(syms.trailer, [lparen.clone(), rparen.clone()])
|
||||
if args:
|
||||
node.insert_child(1, Node(syms.arglist, args))
|
||||
return node
|
||||
|
||||
def Call(func_name, args=None, prefix=None):
|
||||
"""A function call"""
|
||||
node = Node(syms.power, [func_name, ArgList(args)])
|
||||
if prefix is not None:
|
||||
node.prefix = prefix
|
||||
return node
|
||||
|
||||
def Newline():
|
||||
"""A newline literal"""
|
||||
return Leaf(token.NEWLINE, "\n")
|
||||
|
||||
def BlankLine():
|
||||
"""A blank line"""
|
||||
return Leaf(token.NEWLINE, "")
|
||||
|
||||
def Number(n, prefix=None):
|
||||
return Leaf(token.NUMBER, n, prefix=prefix)
|
||||
|
||||
def Subscript(index_node):
|
||||
"""A numeric or string subscript"""
|
||||
return Node(syms.trailer, [Leaf(token.LBRACE, "["),
|
||||
index_node,
|
||||
Leaf(token.RBRACE, "]")])
|
||||
|
||||
def String(string, prefix=None):
|
||||
"""A string leaf"""
|
||||
return Leaf(token.STRING, string, prefix=prefix)
|
||||
|
||||
def ListComp(xp, fp, it, test=None):
|
||||
"""A list comprehension of the form [xp for fp in it if test].
|
||||
|
||||
If test is None, the "if test" part is omitted.
|
||||
"""
|
||||
xp.prefix = ""
|
||||
fp.prefix = " "
|
||||
it.prefix = " "
|
||||
for_leaf = Leaf(token.NAME, "for")
|
||||
for_leaf.prefix = " "
|
||||
in_leaf = Leaf(token.NAME, "in")
|
||||
in_leaf.prefix = " "
|
||||
inner_args = [for_leaf, fp, in_leaf, it]
|
||||
if test:
|
||||
test.prefix = " "
|
||||
if_leaf = Leaf(token.NAME, "if")
|
||||
if_leaf.prefix = " "
|
||||
inner_args.append(Node(syms.comp_if, [if_leaf, test]))
|
||||
inner = Node(syms.listmaker, [xp, Node(syms.comp_for, inner_args)])
|
||||
return Node(syms.atom,
|
||||
[Leaf(token.LBRACE, "["),
|
||||
inner,
|
||||
Leaf(token.RBRACE, "]")])
|
||||
|
||||
def FromImport(package_name, name_leafs):
|
||||
""" Return an import statement in the form:
|
||||
from package import name_leafs"""
|
||||
# XXX: May not handle dotted imports properly (eg, package_name='foo.bar')
|
||||
#assert package_name == '.' or '.' not in package_name, "FromImport has "\
|
||||
# "not been tested with dotted package names -- use at your own "\
|
||||
# "peril!"
|
||||
|
||||
for leaf in name_leafs:
|
||||
# Pull the leaves out of their old tree
|
||||
leaf.remove()
|
||||
|
||||
children = [Leaf(token.NAME, "from"),
|
||||
Leaf(token.NAME, package_name, prefix=" "),
|
||||
Leaf(token.NAME, "import", prefix=" "),
|
||||
Node(syms.import_as_names, name_leafs)]
|
||||
imp = Node(syms.import_from, children)
|
||||
return imp
|
||||
|
||||
def ImportAndCall(node, results, names):
|
||||
"""Returns an import statement and calls a method
|
||||
of the module:
|
||||
|
||||
import module
|
||||
module.name()"""
|
||||
obj = results["obj"].clone()
|
||||
if obj.type == syms.arglist:
|
||||
newarglist = obj.clone()
|
||||
else:
|
||||
newarglist = Node(syms.arglist, [obj.clone()])
|
||||
after = results["after"]
|
||||
if after:
|
||||
after = [n.clone() for n in after]
|
||||
new = Node(syms.power,
|
||||
Attr(Name(names[0]), Name(names[1])) +
|
||||
[Node(syms.trailer,
|
||||
[results["lpar"].clone(),
|
||||
newarglist,
|
||||
results["rpar"].clone()])] + after)
|
||||
new.prefix = node.prefix
|
||||
return new
|
||||
|
||||
|
||||
###########################################################
|
||||
### Determine whether a node represents a given literal
|
||||
###########################################################
|
||||
|
||||
def is_tuple(node):
|
||||
"""Does the node represent a tuple literal?"""
|
||||
if isinstance(node, Node) and node.children == [LParen(), RParen()]:
|
||||
return True
|
||||
return (isinstance(node, Node)
|
||||
and len(node.children) == 3
|
||||
and isinstance(node.children[0], Leaf)
|
||||
and isinstance(node.children[1], Node)
|
||||
and isinstance(node.children[2], Leaf)
|
||||
and node.children[0].value == "("
|
||||
and node.children[2].value == ")")
|
||||
|
||||
def is_list(node):
|
||||
"""Does the node represent a list literal?"""
|
||||
return (isinstance(node, Node)
|
||||
and len(node.children) > 1
|
||||
and isinstance(node.children[0], Leaf)
|
||||
and isinstance(node.children[-1], Leaf)
|
||||
and node.children[0].value == "["
|
||||
and node.children[-1].value == "]")
|
||||
|
||||
|
||||
###########################################################
|
||||
### Misc
|
||||
###########################################################
|
||||
|
||||
def parenthesize(node):
|
||||
return Node(syms.atom, [LParen(), node, RParen()])
|
||||
|
||||
|
||||
consuming_calls = {"sorted", "list", "set", "any", "all", "tuple", "sum",
|
||||
"min", "max", "enumerate"}
|
||||
|
||||
def attr_chain(obj, attr):
|
||||
"""Follow an attribute chain.
|
||||
|
||||
If you have a chain of objects where a.foo -> b, b.foo-> c, etc,
|
||||
use this to iterate over all objects in the chain. Iteration is
|
||||
terminated by getattr(x, attr) is None.
|
||||
|
||||
Args:
|
||||
obj: the starting object
|
||||
attr: the name of the chaining attribute
|
||||
|
||||
Yields:
|
||||
Each successive object in the chain.
|
||||
"""
|
||||
next = getattr(obj, attr)
|
||||
while next:
|
||||
yield next
|
||||
next = getattr(next, attr)
|
||||
|
||||
p0 = """for_stmt< 'for' any 'in' node=any ':' any* >
|
||||
| comp_for< 'for' any 'in' node=any any* >
|
||||
"""
|
||||
p1 = """
|
||||
power<
|
||||
( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
|
||||
'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) )
|
||||
trailer< '(' node=any ')' >
|
||||
any*
|
||||
>
|
||||
"""
|
||||
p2 = """
|
||||
power<
|
||||
( 'sorted' | 'enumerate' )
|
||||
trailer< '(' arglist<node=any any*> ')' >
|
||||
any*
|
||||
>
|
||||
"""
|
||||
pats_built = False
|
||||
def in_special_context(node):
|
||||
""" Returns true if node is in an environment where all that is required
|
||||
of it is being iterable (ie, it doesn't matter if it returns a list
|
||||
or an iterator).
|
||||
See test_map_nochange in test_fixers.py for some examples and tests.
|
||||
"""
|
||||
global p0, p1, p2, pats_built
|
||||
if not pats_built:
|
||||
p0 = patcomp.compile_pattern(p0)
|
||||
p1 = patcomp.compile_pattern(p1)
|
||||
p2 = patcomp.compile_pattern(p2)
|
||||
pats_built = True
|
||||
patterns = [p0, p1, p2]
|
||||
for pattern, parent in zip(patterns, attr_chain(node, "parent")):
|
||||
results = {}
|
||||
if pattern.match(parent, results) and results["node"] is node:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_probably_builtin(node):
|
||||
"""
|
||||
Check that something isn't an attribute or function name etc.
|
||||
"""
|
||||
prev = node.prev_sibling
|
||||
if prev is not None and prev.type == token.DOT:
|
||||
# Attribute lookup.
|
||||
return False
|
||||
parent = node.parent
|
||||
if parent.type in (syms.funcdef, syms.classdef):
|
||||
return False
|
||||
if parent.type == syms.expr_stmt and parent.children[0] is node:
|
||||
# Assignment.
|
||||
return False
|
||||
if parent.type == syms.parameters or \
|
||||
(parent.type == syms.typedargslist and (
|
||||
(prev is not None and prev.type == token.COMMA) or
|
||||
parent.children[0] is node
|
||||
)):
|
||||
# The name of an argument.
|
||||
return False
|
||||
return True
|
||||
|
||||
def find_indentation(node):
|
||||
"""Find the indentation of *node*."""
|
||||
while node is not None:
|
||||
if node.type == syms.suite and len(node.children) > 2:
|
||||
indent = node.children[1]
|
||||
if indent.type == token.INDENT:
|
||||
return indent.value
|
||||
node = node.parent
|
||||
return ""
|
||||
|
||||
###########################################################
|
||||
### The following functions are to find bindings in a suite
|
||||
###########################################################
|
||||
|
||||
def make_suite(node):
|
||||
if node.type == syms.suite:
|
||||
return node
|
||||
node = node.clone()
|
||||
parent, node.parent = node.parent, None
|
||||
suite = Node(syms.suite, [node])
|
||||
suite.parent = parent
|
||||
return suite
|
||||
|
||||
def find_root(node):
|
||||
"""Find the top level namespace."""
|
||||
# Scamper up to the top level namespace
|
||||
while node.type != syms.file_input:
|
||||
node = node.parent
|
||||
if not node:
|
||||
raise ValueError("root found before file_input node was found.")
|
||||
return node
|
||||
|
||||
def does_tree_import(package, name, node):
|
||||
""" Returns true if name is imported from package at the
|
||||
top level of the tree which node belongs to.
|
||||
To cover the case of an import like 'import foo', use
|
||||
None for the package and 'foo' for the name. """
|
||||
binding = find_binding(name, find_root(node), package)
|
||||
return bool(binding)
|
||||
|
||||
def is_import(node):
|
||||
"""Returns true if the node is an import statement."""
|
||||
return node.type in (syms.import_name, syms.import_from)
|
||||
|
||||
def touch_import(package, name, node):
|
||||
""" Works like `does_tree_import` but adds an import statement
|
||||
if it was not imported. """
|
||||
def is_import_stmt(node):
|
||||
return (node.type == syms.simple_stmt and node.children and
|
||||
is_import(node.children[0]))
|
||||
|
||||
root = find_root(node)
|
||||
|
||||
if does_tree_import(package, name, root):
|
||||
return
|
||||
|
||||
# figure out where to insert the new import. First try to find
|
||||
# the first import and then skip to the last one.
|
||||
insert_pos = offset = 0
|
||||
for idx, node in enumerate(root.children):
|
||||
if not is_import_stmt(node):
|
||||
continue
|
||||
for offset, node2 in enumerate(root.children[idx:]):
|
||||
if not is_import_stmt(node2):
|
||||
break
|
||||
insert_pos = idx + offset
|
||||
break
|
||||
|
||||
# if there are no imports where we can insert, find the docstring.
|
||||
# if that also fails, we stick to the beginning of the file
|
||||
if insert_pos == 0:
|
||||
for idx, node in enumerate(root.children):
|
||||
if (node.type == syms.simple_stmt and node.children and
|
||||
node.children[0].type == token.STRING):
|
||||
insert_pos = idx + 1
|
||||
break
|
||||
|
||||
if package is None:
|
||||
import_ = Node(syms.import_name, [
|
||||
Leaf(token.NAME, "import"),
|
||||
Leaf(token.NAME, name, prefix=" ")
|
||||
])
|
||||
else:
|
||||
import_ = FromImport(package, [Leaf(token.NAME, name, prefix=" ")])
|
||||
|
||||
children = [import_, Newline()]
|
||||
root.insert_child(insert_pos, Node(syms.simple_stmt, children))
|
||||
|
||||
|
||||
_def_syms = {syms.classdef, syms.funcdef}
|
||||
def find_binding(name, node, package=None):
|
||||
""" Returns the node which binds variable name, otherwise None.
|
||||
If optional argument package is supplied, only imports will
|
||||
be returned.
|
||||
See test cases for examples."""
|
||||
for child in node.children:
|
||||
ret = None
|
||||
if child.type == syms.for_stmt:
|
||||
if _find(name, child.children[1]):
|
||||
return child
|
||||
n = find_binding(name, make_suite(child.children[-1]), package)
|
||||
if n: ret = n
|
||||
elif child.type in (syms.if_stmt, syms.while_stmt):
|
||||
n = find_binding(name, make_suite(child.children[-1]), package)
|
||||
if n: ret = n
|
||||
elif child.type == syms.try_stmt:
|
||||
n = find_binding(name, make_suite(child.children[2]), package)
|
||||
if n:
|
||||
ret = n
|
||||
else:
|
||||
for i, kid in enumerate(child.children[3:]):
|
||||
if kid.type == token.COLON and kid.value == ":":
|
||||
# i+3 is the colon, i+4 is the suite
|
||||
n = find_binding(name, make_suite(child.children[i+4]), package)
|
||||
if n: ret = n
|
||||
elif child.type in _def_syms and child.children[1].value == name:
|
||||
ret = child
|
||||
elif _is_import_binding(child, name, package):
|
||||
ret = child
|
||||
elif child.type == syms.simple_stmt:
|
||||
ret = find_binding(name, child, package)
|
||||
elif child.type == syms.expr_stmt:
|
||||
if _find(name, child.children[0]):
|
||||
ret = child
|
||||
|
||||
if ret:
|
||||
if not package:
|
||||
return ret
|
||||
if is_import(ret):
|
||||
return ret
|
||||
return None
|
||||
|
||||
_block_syms = {syms.funcdef, syms.classdef, syms.trailer}
|
||||
def _find(name, node):
|
||||
nodes = [node]
|
||||
while nodes:
|
||||
node = nodes.pop()
|
||||
if node.type > 256 and node.type not in _block_syms:
|
||||
nodes.extend(node.children)
|
||||
elif node.type == token.NAME and node.value == name:
|
||||
return node
|
||||
return None
|
||||
|
||||
def _is_import_binding(node, name, package=None):
|
||||
""" Will reuturn node if node will import name, or node
|
||||
will import * from package. None is returned otherwise.
|
||||
See test cases for examples. """
|
||||
|
||||
if node.type == syms.import_name and not package:
|
||||
imp = node.children[1]
|
||||
if imp.type == syms.dotted_as_names:
|
||||
for child in imp.children:
|
||||
if child.type == syms.dotted_as_name:
|
||||
if child.children[2].value == name:
|
||||
return node
|
||||
elif child.type == token.NAME and child.value == name:
|
||||
return node
|
||||
elif imp.type == syms.dotted_as_name:
|
||||
last = imp.children[-1]
|
||||
if last.type == token.NAME and last.value == name:
|
||||
return node
|
||||
elif imp.type == token.NAME and imp.value == name:
|
||||
return node
|
||||
elif node.type == syms.import_from:
|
||||
# str(...) is used to make life easier here, because
|
||||
# from a.b import parses to ['import', ['a', '.', 'b'], ...]
|
||||
if package and str(node.children[1]).strip() != package:
|
||||
return None
|
||||
n = node.children[3]
|
||||
if package and _find("as", n):
|
||||
# See test_from_import_as for explanation
|
||||
return None
|
||||
elif n.type == syms.import_as_names and _find(name, n):
|
||||
return node
|
||||
elif n.type == syms.import_as_name:
|
||||
child = n.children[2]
|
||||
if child.type == token.NAME and child.value == name:
|
||||
return node
|
||||
elif n.type == token.NAME and n.value == name:
|
||||
return node
|
||||
elif package and n.type == token.STAR:
|
||||
return node
|
||||
return None
|
||||
1
Lib/lib2to3/fixes/__init__.py
Normal file
1
Lib/lib2to3/fixes/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Dummy file to make this directory a package.
|
||||
BIN
Lib/lib2to3/fixes/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_apply.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_apply.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_asserts.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_asserts.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_basestring.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_basestring.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_buffer.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_buffer.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_dict.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_dict.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_except.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_except.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_exec.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_exec.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_execfile.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_execfile.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_exitfunc.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_exitfunc.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_filter.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_filter.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_funcattrs.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_funcattrs.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_future.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_future.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_getcwdu.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_getcwdu.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_has_key.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_has_key.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_idioms.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_idioms.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_import.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_import.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_imports.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_imports.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_imports2.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_imports2.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_input.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_input.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_intern.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_intern.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_isinstance.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_isinstance.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_itertools.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_itertools.cpython-37.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_long.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_long.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_map.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_map.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_metaclass.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_metaclass.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_methodattrs.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_methodattrs.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_ne.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_ne.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_next.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_next.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_nonzero.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_nonzero.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_numliterals.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_numliterals.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_operator.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_operator.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_paren.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_paren.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_print.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_print.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_raise.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_raise.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_raw_input.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_raw_input.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_reduce.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_reduce.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_reload.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_reload.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_renames.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_renames.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_repr.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_repr.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_set_literal.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_set_literal.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_standarderror.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_standarderror.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_sys_exc.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_sys_exc.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_throw.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_throw.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_tuple_params.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_tuple_params.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_types.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_types.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_unicode.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_unicode.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_urllib.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_urllib.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_ws_comma.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_ws_comma.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_xrange.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_xrange.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_xreadlines.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_xreadlines.cpython-37.pyc
Normal file
Binary file not shown.
BIN
Lib/lib2to3/fixes/__pycache__/fix_zip.cpython-37.pyc
Normal file
BIN
Lib/lib2to3/fixes/__pycache__/fix_zip.cpython-37.pyc
Normal file
Binary file not shown.
70
Lib/lib2to3/fixes/fix_apply.py
Normal file
70
Lib/lib2to3/fixes/fix_apply.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer for apply().
|
||||
|
||||
This converts apply(func, v, k) into (func)(*v, **k)."""
|
||||
|
||||
# Local imports
|
||||
from .. import pytree
|
||||
from ..pgen2 import token
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Call, Comma, parenthesize
|
||||
|
||||
class FixApply(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
power< 'apply'
|
||||
trailer<
|
||||
'('
|
||||
arglist<
|
||||
(not argument<NAME '=' any>) func=any ','
|
||||
(not argument<NAME '=' any>) args=any [','
|
||||
(not argument<NAME '=' any>) kwds=any] [',']
|
||||
>
|
||||
')'
|
||||
>
|
||||
>
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
syms = self.syms
|
||||
assert results
|
||||
func = results["func"]
|
||||
args = results["args"]
|
||||
kwds = results.get("kwds")
|
||||
# I feel like we should be able to express this logic in the
|
||||
# PATTERN above but I don't know how to do it so...
|
||||
if args:
|
||||
if args.type == self.syms.star_expr:
|
||||
return # Make no change.
|
||||
if (args.type == self.syms.argument and
|
||||
args.children[0].value == '**'):
|
||||
return # Make no change.
|
||||
if kwds and (kwds.type == self.syms.argument and
|
||||
kwds.children[0].value == '**'):
|
||||
return # Make no change.
|
||||
prefix = node.prefix
|
||||
func = func.clone()
|
||||
if (func.type not in (token.NAME, syms.atom) and
|
||||
(func.type != syms.power or
|
||||
func.children[-2].type == token.DOUBLESTAR)):
|
||||
# Need to parenthesize
|
||||
func = parenthesize(func)
|
||||
func.prefix = ""
|
||||
args = args.clone()
|
||||
args.prefix = ""
|
||||
if kwds is not None:
|
||||
kwds = kwds.clone()
|
||||
kwds.prefix = ""
|
||||
l_newargs = [pytree.Leaf(token.STAR, "*"), args]
|
||||
if kwds is not None:
|
||||
l_newargs.extend([Comma(),
|
||||
pytree.Leaf(token.DOUBLESTAR, "**"),
|
||||
kwds])
|
||||
l_newargs[-2].prefix = " " # that's the ** token
|
||||
# XXX Sometimes we could be cleverer, e.g. apply(f, (x, y) + t)
|
||||
# can be translated into f(x, y, *t) instead of f(*(x, y) + t)
|
||||
#new = pytree.Node(syms.power, (func, ArgList(l_newargs)))
|
||||
return Call(func, l_newargs, prefix=prefix)
|
||||
34
Lib/lib2to3/fixes/fix_asserts.py
Normal file
34
Lib/lib2to3/fixes/fix_asserts.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"""Fixer that replaces deprecated unittest method names."""
|
||||
|
||||
# Author: Ezio Melotti
|
||||
|
||||
from ..fixer_base import BaseFix
|
||||
from ..fixer_util import Name
|
||||
|
||||
NAMES = dict(
|
||||
assert_="assertTrue",
|
||||
assertEquals="assertEqual",
|
||||
assertNotEquals="assertNotEqual",
|
||||
assertAlmostEquals="assertAlmostEqual",
|
||||
assertNotAlmostEquals="assertNotAlmostEqual",
|
||||
assertRegexpMatches="assertRegex",
|
||||
assertRaisesRegexp="assertRaisesRegex",
|
||||
failUnlessEqual="assertEqual",
|
||||
failIfEqual="assertNotEqual",
|
||||
failUnlessAlmostEqual="assertAlmostEqual",
|
||||
failIfAlmostEqual="assertNotAlmostEqual",
|
||||
failUnless="assertTrue",
|
||||
failUnlessRaises="assertRaises",
|
||||
failIf="assertFalse",
|
||||
)
|
||||
|
||||
|
||||
class FixAsserts(BaseFix):
|
||||
|
||||
PATTERN = """
|
||||
power< any+ trailer< '.' meth=(%s)> any* >
|
||||
""" % '|'.join(map(repr, NAMES))
|
||||
|
||||
def transform(self, node, results):
|
||||
name = results["meth"][0]
|
||||
name.replace(Name(NAMES[str(name)], prefix=name.prefix))
|
||||
14
Lib/lib2to3/fixes/fix_basestring.py
Normal file
14
Lib/lib2to3/fixes/fix_basestring.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
"""Fixer for basestring -> str."""
|
||||
# Author: Christian Heimes
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name
|
||||
|
||||
class FixBasestring(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = "'basestring'"
|
||||
|
||||
def transform(self, node, results):
|
||||
return Name("str", prefix=node.prefix)
|
||||
22
Lib/lib2to3/fixes/fix_buffer.py
Normal file
22
Lib/lib2to3/fixes/fix_buffer.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Copyright 2007 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer that changes buffer(...) into memoryview(...)."""
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name
|
||||
|
||||
|
||||
class FixBuffer(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
explicit = True # The user must ask for this fixer
|
||||
|
||||
PATTERN = """
|
||||
power< name='buffer' trailer< '(' [any] ')' > any* >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
name = results["name"]
|
||||
name.replace(Name("memoryview", prefix=name.prefix))
|
||||
106
Lib/lib2to3/fixes/fix_dict.py
Normal file
106
Lib/lib2to3/fixes/fix_dict.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Copyright 2007 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer for dict methods.
|
||||
|
||||
d.keys() -> list(d.keys())
|
||||
d.items() -> list(d.items())
|
||||
d.values() -> list(d.values())
|
||||
|
||||
d.iterkeys() -> iter(d.keys())
|
||||
d.iteritems() -> iter(d.items())
|
||||
d.itervalues() -> iter(d.values())
|
||||
|
||||
d.viewkeys() -> d.keys()
|
||||
d.viewitems() -> d.items()
|
||||
d.viewvalues() -> d.values()
|
||||
|
||||
Except in certain very specific contexts: the iter() can be dropped
|
||||
when the context is list(), sorted(), iter() or for...in; the list()
|
||||
can be dropped when the context is list() or sorted() (but not iter()
|
||||
or for...in!). Special contexts that apply to both: list(), sorted(), tuple()
|
||||
set(), any(), all(), sum().
|
||||
|
||||
Note: iter(d.keys()) could be written as iter(d) but since the
|
||||
original d.iterkeys() was also redundant we don't fix this. And there
|
||||
are (rare) contexts where it makes a difference (e.g. when passing it
|
||||
as an argument to a function that introspects the argument).
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from .. import pytree
|
||||
from .. import patcomp
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name, Call, Dot
|
||||
from .. import fixer_util
|
||||
|
||||
|
||||
iter_exempt = fixer_util.consuming_calls | {"iter"}
|
||||
|
||||
|
||||
class FixDict(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
power< head=any+
|
||||
trailer< '.' method=('keys'|'items'|'values'|
|
||||
'iterkeys'|'iteritems'|'itervalues'|
|
||||
'viewkeys'|'viewitems'|'viewvalues') >
|
||||
parens=trailer< '(' ')' >
|
||||
tail=any*
|
||||
>
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
head = results["head"]
|
||||
method = results["method"][0] # Extract node for method name
|
||||
tail = results["tail"]
|
||||
syms = self.syms
|
||||
method_name = method.value
|
||||
isiter = method_name.startswith("iter")
|
||||
isview = method_name.startswith("view")
|
||||
if isiter or isview:
|
||||
method_name = method_name[4:]
|
||||
assert method_name in ("keys", "items", "values"), repr(method)
|
||||
head = [n.clone() for n in head]
|
||||
tail = [n.clone() for n in tail]
|
||||
special = not tail and self.in_special_context(node, isiter)
|
||||
args = head + [pytree.Node(syms.trailer,
|
||||
[Dot(),
|
||||
Name(method_name,
|
||||
prefix=method.prefix)]),
|
||||
results["parens"].clone()]
|
||||
new = pytree.Node(syms.power, args)
|
||||
if not (special or isview):
|
||||
new.prefix = ""
|
||||
new = Call(Name("iter" if isiter else "list"), [new])
|
||||
if tail:
|
||||
new = pytree.Node(syms.power, [new] + tail)
|
||||
new.prefix = node.prefix
|
||||
return new
|
||||
|
||||
P1 = "power< func=NAME trailer< '(' node=any ')' > any* >"
|
||||
p1 = patcomp.compile_pattern(P1)
|
||||
|
||||
P2 = """for_stmt< 'for' any 'in' node=any ':' any* >
|
||||
| comp_for< 'for' any 'in' node=any any* >
|
||||
"""
|
||||
p2 = patcomp.compile_pattern(P2)
|
||||
|
||||
def in_special_context(self, node, isiter):
|
||||
if node.parent is None:
|
||||
return False
|
||||
results = {}
|
||||
if (node.parent.parent is not None and
|
||||
self.p1.match(node.parent.parent, results) and
|
||||
results["node"] is node):
|
||||
if isiter:
|
||||
# iter(d.iterkeys()) -> iter(d.keys()), etc.
|
||||
return results["func"].value in iter_exempt
|
||||
else:
|
||||
# list(d.keys()) -> list(d.keys()), etc.
|
||||
return results["func"].value in fixer_util.consuming_calls
|
||||
if not isiter:
|
||||
return False
|
||||
# for ... in d.iterkeys() -> for ... in d.keys(), etc.
|
||||
return self.p2.match(node.parent, results) and results["node"] is node
|
||||
93
Lib/lib2to3/fixes/fix_except.py
Normal file
93
Lib/lib2to3/fixes/fix_except.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
"""Fixer for except statements with named exceptions.
|
||||
|
||||
The following cases will be converted:
|
||||
|
||||
- "except E, T:" where T is a name:
|
||||
|
||||
except E as T:
|
||||
|
||||
- "except E, T:" where T is not a name, tuple or list:
|
||||
|
||||
except E as t:
|
||||
T = t
|
||||
|
||||
This is done because the target of an "except" clause must be a
|
||||
name.
|
||||
|
||||
- "except E, T:" where T is a tuple or list literal:
|
||||
|
||||
except E as t:
|
||||
T = t.args
|
||||
"""
|
||||
# Author: Collin Winter
|
||||
|
||||
# Local imports
|
||||
from .. import pytree
|
||||
from ..pgen2 import token
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Assign, Attr, Name, is_tuple, is_list, syms
|
||||
|
||||
def find_excepts(nodes):
|
||||
for i, n in enumerate(nodes):
|
||||
if n.type == syms.except_clause:
|
||||
if n.children[0].value == 'except':
|
||||
yield (n, nodes[i+2])
|
||||
|
||||
class FixExcept(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
try_stmt< 'try' ':' (simple_stmt | suite)
|
||||
cleanup=(except_clause ':' (simple_stmt | suite))+
|
||||
tail=(['except' ':' (simple_stmt | suite)]
|
||||
['else' ':' (simple_stmt | suite)]
|
||||
['finally' ':' (simple_stmt | suite)]) >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
syms = self.syms
|
||||
|
||||
tail = [n.clone() for n in results["tail"]]
|
||||
|
||||
try_cleanup = [ch.clone() for ch in results["cleanup"]]
|
||||
for except_clause, e_suite in find_excepts(try_cleanup):
|
||||
if len(except_clause.children) == 4:
|
||||
(E, comma, N) = except_clause.children[1:4]
|
||||
comma.replace(Name("as", prefix=" "))
|
||||
|
||||
if N.type != token.NAME:
|
||||
# Generate a new N for the except clause
|
||||
new_N = Name(self.new_name(), prefix=" ")
|
||||
target = N.clone()
|
||||
target.prefix = ""
|
||||
N.replace(new_N)
|
||||
new_N = new_N.clone()
|
||||
|
||||
# Insert "old_N = new_N" as the first statement in
|
||||
# the except body. This loop skips leading whitespace
|
||||
# and indents
|
||||
#TODO(cwinter) suite-cleanup
|
||||
suite_stmts = e_suite.children
|
||||
for i, stmt in enumerate(suite_stmts):
|
||||
if isinstance(stmt, pytree.Node):
|
||||
break
|
||||
|
||||
# The assignment is different if old_N is a tuple or list
|
||||
# In that case, the assignment is old_N = new_N.args
|
||||
if is_tuple(N) or is_list(N):
|
||||
assign = Assign(target, Attr(new_N, Name('args')))
|
||||
else:
|
||||
assign = Assign(target, new_N)
|
||||
|
||||
#TODO(cwinter) stopgap until children becomes a smart list
|
||||
for child in reversed(suite_stmts[:i]):
|
||||
e_suite.insert_child(0, child)
|
||||
e_suite.insert_child(i, assign)
|
||||
elif N.prefix == "":
|
||||
# No space after a comma is legal; no space after "as",
|
||||
# not so much.
|
||||
N.prefix = " "
|
||||
|
||||
#TODO(cwinter) fix this when children becomes a smart list
|
||||
children = [c.clone() for c in node.children[:3]] + try_cleanup + tail
|
||||
return pytree.Node(node.type, children)
|
||||
39
Lib/lib2to3/fixes/fix_exec.py
Normal file
39
Lib/lib2to3/fixes/fix_exec.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer for exec.
|
||||
|
||||
This converts usages of the exec statement into calls to a built-in
|
||||
exec() function.
|
||||
|
||||
exec code in ns1, ns2 -> exec(code, ns1, ns2)
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Comma, Name, Call
|
||||
|
||||
|
||||
class FixExec(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
exec_stmt< 'exec' a=any 'in' b=any [',' c=any] >
|
||||
|
|
||||
exec_stmt< 'exec' (not atom<'(' [any] ')'>) a=any >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
assert results
|
||||
syms = self.syms
|
||||
a = results["a"]
|
||||
b = results.get("b")
|
||||
c = results.get("c")
|
||||
args = [a.clone()]
|
||||
args[0].prefix = ""
|
||||
if b is not None:
|
||||
args.extend([Comma(), b.clone()])
|
||||
if c is not None:
|
||||
args.extend([Comma(), c.clone()])
|
||||
|
||||
return Call(Name("exec"), args, prefix=node.prefix)
|
||||
53
Lib/lib2to3/fixes/fix_execfile.py
Normal file
53
Lib/lib2to3/fixes/fix_execfile.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer for execfile.
|
||||
|
||||
This converts usages of the execfile function into calls to the built-in
|
||||
exec() function.
|
||||
"""
|
||||
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import (Comma, Name, Call, LParen, RParen, Dot, Node,
|
||||
ArgList, String, syms)
|
||||
|
||||
|
||||
class FixExecfile(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
power< 'execfile' trailer< '(' arglist< filename=any [',' globals=any [',' locals=any ] ] > ')' > >
|
||||
|
|
||||
power< 'execfile' trailer< '(' filename=any ')' > >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
assert results
|
||||
filename = results["filename"]
|
||||
globals = results.get("globals")
|
||||
locals = results.get("locals")
|
||||
|
||||
# Copy over the prefix from the right parentheses end of the execfile
|
||||
# call.
|
||||
execfile_paren = node.children[-1].children[-1].clone()
|
||||
# Construct open().read().
|
||||
open_args = ArgList([filename.clone(), Comma(), String('"rb"', ' ')],
|
||||
rparen=execfile_paren)
|
||||
open_call = Node(syms.power, [Name("open"), open_args])
|
||||
read = [Node(syms.trailer, [Dot(), Name('read')]),
|
||||
Node(syms.trailer, [LParen(), RParen()])]
|
||||
open_expr = [open_call] + read
|
||||
# Wrap the open call in a compile call. This is so the filename will be
|
||||
# preserved in the execed code.
|
||||
filename_arg = filename.clone()
|
||||
filename_arg.prefix = " "
|
||||
exec_str = String("'exec'", " ")
|
||||
compile_args = open_expr + [Comma(), filename_arg, Comma(), exec_str]
|
||||
compile_call = Call(Name("compile"), compile_args, "")
|
||||
# Finally, replace the execfile call with an exec call.
|
||||
args = [compile_call]
|
||||
if globals is not None:
|
||||
args.extend([Comma(), globals.clone()])
|
||||
if locals is not None:
|
||||
args.extend([Comma(), locals.clone()])
|
||||
return Call(Name("exec"), args, prefix=node.prefix)
|
||||
72
Lib/lib2to3/fixes/fix_exitfunc.py
Normal file
72
Lib/lib2to3/fixes/fix_exitfunc.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
"""
|
||||
Convert use of sys.exitfunc to use the atexit module.
|
||||
"""
|
||||
|
||||
# Author: Benjamin Peterson
|
||||
|
||||
from lib2to3 import pytree, fixer_base
|
||||
from lib2to3.fixer_util import Name, Attr, Call, Comma, Newline, syms
|
||||
|
||||
|
||||
class FixExitfunc(fixer_base.BaseFix):
|
||||
keep_line_order = True
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
(
|
||||
sys_import=import_name<'import'
|
||||
('sys'
|
||||
|
|
||||
dotted_as_names< (any ',')* 'sys' (',' any)* >
|
||||
)
|
||||
>
|
||||
|
|
||||
expr_stmt<
|
||||
power< 'sys' trailer< '.' 'exitfunc' > >
|
||||
'=' func=any >
|
||||
)
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super(FixExitfunc, self).__init__(*args)
|
||||
|
||||
def start_tree(self, tree, filename):
|
||||
super(FixExitfunc, self).start_tree(tree, filename)
|
||||
self.sys_import = None
|
||||
|
||||
def transform(self, node, results):
|
||||
# First, find the sys import. We'll just hope it's global scope.
|
||||
if "sys_import" in results:
|
||||
if self.sys_import is None:
|
||||
self.sys_import = results["sys_import"]
|
||||
return
|
||||
|
||||
func = results["func"].clone()
|
||||
func.prefix = ""
|
||||
register = pytree.Node(syms.power,
|
||||
Attr(Name("atexit"), Name("register"))
|
||||
)
|
||||
call = Call(register, [func], node.prefix)
|
||||
node.replace(call)
|
||||
|
||||
if self.sys_import is None:
|
||||
# That's interesting.
|
||||
self.warning(node, "Can't find sys import; Please add an atexit "
|
||||
"import at the top of your file.")
|
||||
return
|
||||
|
||||
# Now add an atexit import after the sys import.
|
||||
names = self.sys_import.children[1]
|
||||
if names.type == syms.dotted_as_names:
|
||||
names.append_child(Comma())
|
||||
names.append_child(Name("atexit", " "))
|
||||
else:
|
||||
containing_stmt = self.sys_import.parent
|
||||
position = containing_stmt.children.index(self.sys_import)
|
||||
stmt_container = containing_stmt.parent
|
||||
new_import = pytree.Node(syms.import_name,
|
||||
[Name("import"), Name("atexit", " ")]
|
||||
)
|
||||
new = pytree.Node(syms.simple_stmt, [new_import])
|
||||
containing_stmt.insert_child(position + 1, Newline())
|
||||
containing_stmt.insert_child(position + 2, new)
|
||||
90
Lib/lib2to3/fixes/fix_filter.py
Normal file
90
Lib/lib2to3/fixes/fix_filter.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Copyright 2007 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer that changes filter(F, X) into list(filter(F, X)).
|
||||
|
||||
We avoid the transformation if the filter() 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
|
||||
filter(F, X) to return a string if X is a string and a tuple if X is a
|
||||
tuple. That would require type inference, which we don't do. Let
|
||||
Python 2.6 figure it out.
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..pytree import Node
|
||||
from ..pygram import python_symbols as syms
|
||||
from ..fixer_util import Name, ArgList, ListComp, in_special_context
|
||||
|
||||
|
||||
class FixFilter(fixer_base.ConditionalFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
filter_lambda=power<
|
||||
'filter'
|
||||
trailer<
|
||||
'('
|
||||
arglist<
|
||||
lambdef< 'lambda'
|
||||
(fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any
|
||||
>
|
||||
','
|
||||
it=any
|
||||
>
|
||||
')'
|
||||
>
|
||||
[extra_trailers=trailer*]
|
||||
>
|
||||
|
|
||||
power<
|
||||
'filter'
|
||||
trailer< '(' arglist< none='None' ',' seq=any > ')' >
|
||||
[extra_trailers=trailer*]
|
||||
>
|
||||
|
|
||||
power<
|
||||
'filter'
|
||||
args=trailer< '(' [any] ')' >
|
||||
[extra_trailers=trailer*]
|
||||
>
|
||||
"""
|
||||
|
||||
skip_on = "future_builtins.filter"
|
||||
|
||||
def transform(self, node, results):
|
||||
if self.should_skip(node):
|
||||
return
|
||||
|
||||
trailers = []
|
||||
if 'extra_trailers' in results:
|
||||
for t in results['extra_trailers']:
|
||||
trailers.append(t.clone())
|
||||
|
||||
if "filter_lambda" in results:
|
||||
new = ListComp(results.get("fp").clone(),
|
||||
results.get("fp").clone(),
|
||||
results.get("it").clone(),
|
||||
results.get("xp").clone())
|
||||
new = Node(syms.power, [new] + trailers, prefix="")
|
||||
|
||||
elif "none" in results:
|
||||
new = ListComp(Name("_f"),
|
||||
Name("_f"),
|
||||
results["seq"].clone(),
|
||||
Name("_f"))
|
||||
new = Node(syms.power, [new] + trailers, prefix="")
|
||||
|
||||
else:
|
||||
if in_special_context(node):
|
||||
return None
|
||||
|
||||
args = results['args'].clone()
|
||||
new = Node(syms.power, [Name("filter"), args], prefix="")
|
||||
new = Node(syms.power, [Name("list"), ArgList([new])] + trailers)
|
||||
new.prefix = ""
|
||||
new.prefix = node.prefix
|
||||
return new
|
||||
21
Lib/lib2to3/fixes/fix_funcattrs.py
Normal file
21
Lib/lib2to3/fixes/fix_funcattrs.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
"""Fix function attribute names (f.func_x -> f.__x__)."""
|
||||
# Author: Collin Winter
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name
|
||||
|
||||
|
||||
class FixFuncattrs(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
power< any+ trailer< '.' attr=('func_closure' | 'func_doc' | 'func_globals'
|
||||
| 'func_name' | 'func_defaults' | 'func_code'
|
||||
| 'func_dict') > any* >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
attr = results["attr"][0]
|
||||
attr.replace(Name(("__%s__" % attr.value[5:]),
|
||||
prefix=attr.prefix))
|
||||
22
Lib/lib2to3/fixes/fix_future.py
Normal file
22
Lib/lib2to3/fixes/fix_future.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
"""Remove __future__ imports
|
||||
|
||||
from __future__ import foo is replaced with an empty line.
|
||||
"""
|
||||
# Author: Christian Heimes
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import BlankLine
|
||||
|
||||
class FixFuture(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """import_from< 'from' module_name="__future__" 'import' any >"""
|
||||
|
||||
# This should be run last -- some things check for the import
|
||||
run_order = 10
|
||||
|
||||
def transform(self, node, results):
|
||||
new = BlankLine()
|
||||
new.prefix = node.prefix
|
||||
return new
|
||||
19
Lib/lib2to3/fixes/fix_getcwdu.py
Normal file
19
Lib/lib2to3/fixes/fix_getcwdu.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
"""
|
||||
Fixer that changes os.getcwdu() to os.getcwd().
|
||||
"""
|
||||
# Author: Victor Stinner
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name
|
||||
|
||||
class FixGetcwdu(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
power< 'os' trailer< dot='.' name='getcwdu' > any* >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
name = results["name"]
|
||||
name.replace(Name("getcwd", prefix=name.prefix))
|
||||
109
Lib/lib2to3/fixes/fix_has_key.py
Normal file
109
Lib/lib2to3/fixes/fix_has_key.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer for has_key().
|
||||
|
||||
Calls to .has_key() methods are expressed in terms of the 'in'
|
||||
operator:
|
||||
|
||||
d.has_key(k) -> k in d
|
||||
|
||||
CAVEATS:
|
||||
1) While the primary target of this fixer is dict.has_key(), the
|
||||
fixer will change any has_key() method call, regardless of its
|
||||
class.
|
||||
|
||||
2) Cases like this will not be converted:
|
||||
|
||||
m = d.has_key
|
||||
if m(k):
|
||||
...
|
||||
|
||||
Only *calls* to has_key() are converted. While it is possible to
|
||||
convert the above to something like
|
||||
|
||||
m = d.__contains__
|
||||
if m(k):
|
||||
...
|
||||
|
||||
this is currently not done.
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from .. import pytree
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name, parenthesize
|
||||
|
||||
|
||||
class FixHasKey(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
anchor=power<
|
||||
before=any+
|
||||
trailer< '.' 'has_key' >
|
||||
trailer<
|
||||
'('
|
||||
( not(arglist | argument<any '=' any>) arg=any
|
||||
| arglist<(not argument<any '=' any>) arg=any ','>
|
||||
)
|
||||
')'
|
||||
>
|
||||
after=any*
|
||||
>
|
||||
|
|
||||
negation=not_test<
|
||||
'not'
|
||||
anchor=power<
|
||||
before=any+
|
||||
trailer< '.' 'has_key' >
|
||||
trailer<
|
||||
'('
|
||||
( not(arglist | argument<any '=' any>) arg=any
|
||||
| arglist<(not argument<any '=' any>) arg=any ','>
|
||||
)
|
||||
')'
|
||||
>
|
||||
>
|
||||
>
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
assert results
|
||||
syms = self.syms
|
||||
if (node.parent.type == syms.not_test and
|
||||
self.pattern.match(node.parent)):
|
||||
# Don't transform a node matching the first alternative of the
|
||||
# pattern when its parent matches the second alternative
|
||||
return None
|
||||
negation = results.get("negation")
|
||||
anchor = results["anchor"]
|
||||
prefix = node.prefix
|
||||
before = [n.clone() for n in results["before"]]
|
||||
arg = results["arg"].clone()
|
||||
after = results.get("after")
|
||||
if after:
|
||||
after = [n.clone() for n in after]
|
||||
if arg.type in (syms.comparison, syms.not_test, syms.and_test,
|
||||
syms.or_test, syms.test, syms.lambdef, syms.argument):
|
||||
arg = parenthesize(arg)
|
||||
if len(before) == 1:
|
||||
before = before[0]
|
||||
else:
|
||||
before = pytree.Node(syms.power, before)
|
||||
before.prefix = " "
|
||||
n_op = Name("in", prefix=" ")
|
||||
if negation:
|
||||
n_not = Name("not", prefix=" ")
|
||||
n_op = pytree.Node(syms.comp_op, (n_not, n_op))
|
||||
new = pytree.Node(syms.comparison, (arg, n_op, before))
|
||||
if after:
|
||||
new = parenthesize(new)
|
||||
new = pytree.Node(syms.power, (new,) + tuple(after))
|
||||
if node.parent.type in (syms.comparison, syms.expr, syms.xor_expr,
|
||||
syms.and_expr, syms.shift_expr,
|
||||
syms.arith_expr, syms.term,
|
||||
syms.factor, syms.power):
|
||||
new = parenthesize(new)
|
||||
new.prefix = prefix
|
||||
return new
|
||||
152
Lib/lib2to3/fixes/fix_idioms.py
Normal file
152
Lib/lib2to3/fixes/fix_idioms.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
"""Adjust some old Python 2 idioms to their modern counterparts.
|
||||
|
||||
* Change some type comparisons to isinstance() calls:
|
||||
type(x) == T -> isinstance(x, T)
|
||||
type(x) is T -> isinstance(x, T)
|
||||
type(x) != T -> not isinstance(x, T)
|
||||
type(x) is not T -> not isinstance(x, T)
|
||||
|
||||
* Change "while 1:" into "while True:".
|
||||
|
||||
* Change both
|
||||
|
||||
v = list(EXPR)
|
||||
v.sort()
|
||||
foo(v)
|
||||
|
||||
and the more general
|
||||
|
||||
v = EXPR
|
||||
v.sort()
|
||||
foo(v)
|
||||
|
||||
into
|
||||
|
||||
v = sorted(EXPR)
|
||||
foo(v)
|
||||
"""
|
||||
# Author: Jacques Frechet, Collin Winter
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Call, Comma, Name, Node, BlankLine, syms
|
||||
|
||||
CMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)"
|
||||
TYPE = "power< 'type' trailer< '(' x=any ')' > >"
|
||||
|
||||
class FixIdioms(fixer_base.BaseFix):
|
||||
explicit = True # The user must ask for this fixer
|
||||
|
||||
PATTERN = r"""
|
||||
isinstance=comparison< %s %s T=any >
|
||||
|
|
||||
isinstance=comparison< T=any %s %s >
|
||||
|
|
||||
while_stmt< 'while' while='1' ':' any+ >
|
||||
|
|
||||
sorted=any<
|
||||
any*
|
||||
simple_stmt<
|
||||
expr_stmt< id1=any '='
|
||||
power< list='list' trailer< '(' (not arglist<any+>) any ')' > >
|
||||
>
|
||||
'\n'
|
||||
>
|
||||
sort=
|
||||
simple_stmt<
|
||||
power< id2=any
|
||||
trailer< '.' 'sort' > trailer< '(' ')' >
|
||||
>
|
||||
'\n'
|
||||
>
|
||||
next=any*
|
||||
>
|
||||
|
|
||||
sorted=any<
|
||||
any*
|
||||
simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' >
|
||||
sort=
|
||||
simple_stmt<
|
||||
power< id2=any
|
||||
trailer< '.' 'sort' > trailer< '(' ')' >
|
||||
>
|
||||
'\n'
|
||||
>
|
||||
next=any*
|
||||
>
|
||||
""" % (TYPE, CMP, CMP, TYPE)
|
||||
|
||||
def match(self, node):
|
||||
r = super(FixIdioms, self).match(node)
|
||||
# If we've matched one of the sort/sorted subpatterns above, we
|
||||
# want to reject matches where the initial assignment and the
|
||||
# subsequent .sort() call involve different identifiers.
|
||||
if r and "sorted" in r:
|
||||
if r["id1"] == r["id2"]:
|
||||
return r
|
||||
return None
|
||||
return r
|
||||
|
||||
def transform(self, node, results):
|
||||
if "isinstance" in results:
|
||||
return self.transform_isinstance(node, results)
|
||||
elif "while" in results:
|
||||
return self.transform_while(node, results)
|
||||
elif "sorted" in results:
|
||||
return self.transform_sort(node, results)
|
||||
else:
|
||||
raise RuntimeError("Invalid match")
|
||||
|
||||
def transform_isinstance(self, node, results):
|
||||
x = results["x"].clone() # The thing inside of type()
|
||||
T = results["T"].clone() # The type being compared against
|
||||
x.prefix = ""
|
||||
T.prefix = " "
|
||||
test = Call(Name("isinstance"), [x, Comma(), T])
|
||||
if "n" in results:
|
||||
test.prefix = " "
|
||||
test = Node(syms.not_test, [Name("not"), test])
|
||||
test.prefix = node.prefix
|
||||
return test
|
||||
|
||||
def transform_while(self, node, results):
|
||||
one = results["while"]
|
||||
one.replace(Name("True", prefix=one.prefix))
|
||||
|
||||
def transform_sort(self, node, results):
|
||||
sort_stmt = results["sort"]
|
||||
next_stmt = results["next"]
|
||||
list_call = results.get("list")
|
||||
simple_expr = results.get("expr")
|
||||
|
||||
if list_call:
|
||||
list_call.replace(Name("sorted", prefix=list_call.prefix))
|
||||
elif simple_expr:
|
||||
new = simple_expr.clone()
|
||||
new.prefix = ""
|
||||
simple_expr.replace(Call(Name("sorted"), [new],
|
||||
prefix=simple_expr.prefix))
|
||||
else:
|
||||
raise RuntimeError("should not have reached here")
|
||||
sort_stmt.remove()
|
||||
|
||||
btwn = sort_stmt.prefix
|
||||
# Keep any prefix lines between the sort_stmt and the list_call and
|
||||
# shove them right after the sorted() call.
|
||||
if "\n" in btwn:
|
||||
if next_stmt:
|
||||
# The new prefix should be everything from the sort_stmt's
|
||||
# prefix up to the last newline, then the old prefix after a new
|
||||
# line.
|
||||
prefix_lines = (btwn.rpartition("\n")[0], next_stmt[0].prefix)
|
||||
next_stmt[0].prefix = "\n".join(prefix_lines)
|
||||
else:
|
||||
assert list_call.parent
|
||||
assert list_call.next_sibling is None
|
||||
# Put a blank line after list_call and set its prefix.
|
||||
end_line = BlankLine()
|
||||
list_call.parent.append_child(end_line)
|
||||
assert list_call.next_sibling is end_line
|
||||
# The new prefix should be everything up to the first new line
|
||||
# of sort_stmt's prefix.
|
||||
end_line.prefix = btwn.rpartition("\n")[0]
|
||||
99
Lib/lib2to3/fixes/fix_import.py
Normal file
99
Lib/lib2to3/fixes/fix_import.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
"""Fixer for import statements.
|
||||
If spam is being imported from the local directory, this import:
|
||||
from spam import eggs
|
||||
Becomes:
|
||||
from .spam import eggs
|
||||
|
||||
And this import:
|
||||
import spam
|
||||
Becomes:
|
||||
from . import spam
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from os.path import dirname, join, exists, sep
|
||||
from ..fixer_util import FromImport, syms, token
|
||||
|
||||
|
||||
def traverse_imports(names):
|
||||
"""
|
||||
Walks over all the names imported in a dotted_as_names node.
|
||||
"""
|
||||
pending = [names]
|
||||
while pending:
|
||||
node = pending.pop()
|
||||
if node.type == token.NAME:
|
||||
yield node.value
|
||||
elif node.type == syms.dotted_name:
|
||||
yield "".join([ch.value for ch in node.children])
|
||||
elif node.type == syms.dotted_as_name:
|
||||
pending.append(node.children[0])
|
||||
elif node.type == syms.dotted_as_names:
|
||||
pending.extend(node.children[::-2])
|
||||
else:
|
||||
raise AssertionError("unknown node type")
|
||||
|
||||
|
||||
class FixImport(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
import_from< 'from' imp=any 'import' ['('] any [')'] >
|
||||
|
|
||||
import_name< 'import' imp=any >
|
||||
"""
|
||||
|
||||
def start_tree(self, tree, name):
|
||||
super(FixImport, self).start_tree(tree, name)
|
||||
self.skip = "absolute_import" in tree.future_features
|
||||
|
||||
def transform(self, node, results):
|
||||
if self.skip:
|
||||
return
|
||||
imp = results['imp']
|
||||
|
||||
if node.type == syms.import_from:
|
||||
# Some imps are top-level (eg: 'import ham')
|
||||
# some are first level (eg: 'import ham.eggs')
|
||||
# some are third level (eg: 'import ham.eggs as spam')
|
||||
# Hence, the loop
|
||||
while not hasattr(imp, 'value'):
|
||||
imp = imp.children[0]
|
||||
if self.probably_a_local_import(imp.value):
|
||||
imp.value = "." + imp.value
|
||||
imp.changed()
|
||||
else:
|
||||
have_local = False
|
||||
have_absolute = False
|
||||
for mod_name in traverse_imports(imp):
|
||||
if self.probably_a_local_import(mod_name):
|
||||
have_local = True
|
||||
else:
|
||||
have_absolute = True
|
||||
if have_absolute:
|
||||
if have_local:
|
||||
# We won't handle both sibling and absolute imports in the
|
||||
# same statement at the moment.
|
||||
self.warning(node, "absolute and local imports together")
|
||||
return
|
||||
|
||||
new = FromImport(".", [imp])
|
||||
new.prefix = node.prefix
|
||||
return new
|
||||
|
||||
def probably_a_local_import(self, imp_name):
|
||||
if imp_name.startswith("."):
|
||||
# Relative imports are certainly not local imports.
|
||||
return False
|
||||
imp_name = imp_name.split(".", 1)[0]
|
||||
base_path = dirname(self.filename)
|
||||
base_path = join(base_path, imp_name)
|
||||
# If there is no __init__.py next to the file its not in a package
|
||||
# so can't be a relative import.
|
||||
if not exists(join(dirname(base_path), "__init__.py")):
|
||||
return False
|
||||
for ext in [".py", sep, ".pyc", ".so", ".sl", ".pyd"]:
|
||||
if exists(base_path + ext):
|
||||
return True
|
||||
return False
|
||||
145
Lib/lib2to3/fixes/fix_imports.py
Normal file
145
Lib/lib2to3/fixes/fix_imports.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
"""Fix incompatible imports and module references."""
|
||||
# Authors: Collin Winter, Nick Edds
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name, attr_chain
|
||||
|
||||
MAPPING = {'StringIO': 'io',
|
||||
'cStringIO': 'io',
|
||||
'cPickle': 'pickle',
|
||||
'__builtin__' : 'builtins',
|
||||
'copy_reg': 'copyreg',
|
||||
'Queue': 'queue',
|
||||
'SocketServer': 'socketserver',
|
||||
'ConfigParser': 'configparser',
|
||||
'repr': 'reprlib',
|
||||
'FileDialog': 'tkinter.filedialog',
|
||||
'tkFileDialog': 'tkinter.filedialog',
|
||||
'SimpleDialog': 'tkinter.simpledialog',
|
||||
'tkSimpleDialog': 'tkinter.simpledialog',
|
||||
'tkColorChooser': 'tkinter.colorchooser',
|
||||
'tkCommonDialog': 'tkinter.commondialog',
|
||||
'Dialog': 'tkinter.dialog',
|
||||
'Tkdnd': 'tkinter.dnd',
|
||||
'tkFont': 'tkinter.font',
|
||||
'tkMessageBox': 'tkinter.messagebox',
|
||||
'ScrolledText': 'tkinter.scrolledtext',
|
||||
'Tkconstants': 'tkinter.constants',
|
||||
'Tix': 'tkinter.tix',
|
||||
'ttk': 'tkinter.ttk',
|
||||
'Tkinter': 'tkinter',
|
||||
'markupbase': '_markupbase',
|
||||
'_winreg': 'winreg',
|
||||
'thread': '_thread',
|
||||
'dummy_thread': '_dummy_thread',
|
||||
# anydbm and whichdb are handled by fix_imports2
|
||||
'dbhash': 'dbm.bsd',
|
||||
'dumbdbm': 'dbm.dumb',
|
||||
'dbm': 'dbm.ndbm',
|
||||
'gdbm': 'dbm.gnu',
|
||||
'xmlrpclib': 'xmlrpc.client',
|
||||
'DocXMLRPCServer': 'xmlrpc.server',
|
||||
'SimpleXMLRPCServer': 'xmlrpc.server',
|
||||
'httplib': 'http.client',
|
||||
'htmlentitydefs' : 'html.entities',
|
||||
'HTMLParser' : 'html.parser',
|
||||
'Cookie': 'http.cookies',
|
||||
'cookielib': 'http.cookiejar',
|
||||
'BaseHTTPServer': 'http.server',
|
||||
'SimpleHTTPServer': 'http.server',
|
||||
'CGIHTTPServer': 'http.server',
|
||||
#'test.test_support': 'test.support',
|
||||
'commands': 'subprocess',
|
||||
'UserString' : 'collections',
|
||||
'UserList' : 'collections',
|
||||
'urlparse' : 'urllib.parse',
|
||||
'robotparser' : 'urllib.robotparser',
|
||||
}
|
||||
|
||||
|
||||
def alternates(members):
|
||||
return "(" + "|".join(map(repr, members)) + ")"
|
||||
|
||||
|
||||
def build_pattern(mapping=MAPPING):
|
||||
mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
|
||||
bare_names = alternates(mapping.keys())
|
||||
|
||||
yield """name_import=import_name< 'import' ((%s) |
|
||||
multiple_imports=dotted_as_names< any* (%s) any* >) >
|
||||
""" % (mod_list, mod_list)
|
||||
yield """import_from< 'from' (%s) 'import' ['(']
|
||||
( any | import_as_name< any 'as' any > |
|
||||
import_as_names< any* >) [')'] >
|
||||
""" % mod_list
|
||||
yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
|
||||
multiple_imports=dotted_as_names<
|
||||
any* dotted_as_name< (%s) 'as' any > any* >) >
|
||||
""" % (mod_list, mod_list)
|
||||
|
||||
# Find usages of module members in code e.g. thread.foo(bar)
|
||||
yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
|
||||
|
||||
|
||||
class FixImports(fixer_base.BaseFix):
|
||||
|
||||
BM_compatible = True
|
||||
keep_line_order = True
|
||||
# This is overridden in fix_imports2.
|
||||
mapping = MAPPING
|
||||
|
||||
# We want to run this fixer late, so fix_import doesn't try to make stdlib
|
||||
# renames into relative imports.
|
||||
run_order = 6
|
||||
|
||||
def build_pattern(self):
|
||||
return "|".join(build_pattern(self.mapping))
|
||||
|
||||
def compile_pattern(self):
|
||||
# We override this, so MAPPING can be pragmatically altered and the
|
||||
# changes will be reflected in PATTERN.
|
||||
self.PATTERN = self.build_pattern()
|
||||
super(FixImports, self).compile_pattern()
|
||||
|
||||
# Don't match the node if it's within another match.
|
||||
def match(self, node):
|
||||
match = super(FixImports, self).match
|
||||
results = match(node)
|
||||
if results:
|
||||
# Module usage could be in the trailer of an attribute lookup, so we
|
||||
# might have nested matches when "bare_with_attr" is present.
|
||||
if "bare_with_attr" not in results and \
|
||||
any(match(obj) for obj in attr_chain(node, "parent")):
|
||||
return False
|
||||
return results
|
||||
return False
|
||||
|
||||
def start_tree(self, tree, filename):
|
||||
super(FixImports, self).start_tree(tree, filename)
|
||||
self.replace = {}
|
||||
|
||||
def transform(self, node, results):
|
||||
import_mod = results.get("module_name")
|
||||
if import_mod:
|
||||
mod_name = import_mod.value
|
||||
new_name = self.mapping[mod_name]
|
||||
import_mod.replace(Name(new_name, prefix=import_mod.prefix))
|
||||
if "name_import" in results:
|
||||
# If it's not a "from x import x, y" or "import x as y" import,
|
||||
# marked its usage to be replaced.
|
||||
self.replace[mod_name] = new_name
|
||||
if "multiple_imports" in results:
|
||||
# This is a nasty hack to fix multiple imports on a line (e.g.,
|
||||
# "import StringIO, urlparse"). The problem is that I can't
|
||||
# figure out an easy way to make a pattern recognize the keys of
|
||||
# MAPPING randomly sprinkled in an import statement.
|
||||
results = self.match(node)
|
||||
if results:
|
||||
self.transform(node, results)
|
||||
else:
|
||||
# Replace usage of the module.
|
||||
bare_name = results["bare_with_attr"][0]
|
||||
new_name = self.replace.get(bare_name.value)
|
||||
if new_name:
|
||||
bare_name.replace(Name(new_name, prefix=bare_name.prefix))
|
||||
16
Lib/lib2to3/fixes/fix_imports2.py
Normal file
16
Lib/lib2to3/fixes/fix_imports2.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""Fix incompatible imports and module references that must be fixed after
|
||||
fix_imports."""
|
||||
from . import fix_imports
|
||||
|
||||
|
||||
MAPPING = {
|
||||
'whichdb': 'dbm',
|
||||
'anydbm': 'dbm',
|
||||
}
|
||||
|
||||
|
||||
class FixImports2(fix_imports.FixImports):
|
||||
|
||||
run_order = 7
|
||||
|
||||
mapping = MAPPING
|
||||
26
Lib/lib2to3/fixes/fix_input.py
Normal file
26
Lib/lib2to3/fixes/fix_input.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"""Fixer that changes input(...) into eval(input(...))."""
|
||||
# Author: Andre Roberge
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Call, Name
|
||||
from .. import patcomp
|
||||
|
||||
|
||||
context = patcomp.compile_pattern("power< 'eval' trailer< '(' any ')' > >")
|
||||
|
||||
|
||||
class FixInput(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
PATTERN = """
|
||||
power< 'input' args=trailer< '(' [any] ')' > >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
# If we're already wrapped in an eval() call, we're done.
|
||||
if context.match(node.parent.parent):
|
||||
return
|
||||
|
||||
new = node.clone()
|
||||
new.prefix = ""
|
||||
return Call(Name("eval"), [new], prefix=node.prefix)
|
||||
41
Lib/lib2to3/fixes/fix_intern.py
Normal file
41
Lib/lib2to3/fixes/fix_intern.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Copyright 2006 Georg Brandl.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer for intern().
|
||||
|
||||
intern(s) -> sys.intern(s)"""
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import ImportAndCall, touch_import
|
||||
|
||||
|
||||
class FixIntern(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
order = "pre"
|
||||
|
||||
PATTERN = """
|
||||
power< 'intern'
|
||||
trailer< lpar='('
|
||||
( not(arglist | argument<any '=' any>) obj=any
|
||||
| obj=arglist<(not argument<any '=' any>) any ','> )
|
||||
rpar=')' >
|
||||
after=any*
|
||||
>
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
if results:
|
||||
# I feel like we should be able to express this logic in the
|
||||
# PATTERN above but I don't know how to do it so...
|
||||
obj = results['obj']
|
||||
if obj:
|
||||
if obj.type == self.syms.star_expr:
|
||||
return # Make no change.
|
||||
if (obj.type == self.syms.argument and
|
||||
obj.children[0].value == '**'):
|
||||
return # Make no change.
|
||||
names = ('sys', 'intern')
|
||||
new = ImportAndCall(node, results, names)
|
||||
touch_import(None, 'sys', node)
|
||||
return new
|
||||
52
Lib/lib2to3/fixes/fix_isinstance.py
Normal file
52
Lib/lib2to3/fixes/fix_isinstance.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2008 Armin Ronacher.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer that cleans up a tuple argument to isinstance after the tokens
|
||||
in it were fixed. This is mainly used to remove double occurrences of
|
||||
tokens as a leftover of the long -> int / unicode -> str conversion.
|
||||
|
||||
eg. isinstance(x, (int, long)) -> isinstance(x, (int, int))
|
||||
-> isinstance(x, int)
|
||||
"""
|
||||
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import token
|
||||
|
||||
|
||||
class FixIsinstance(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
PATTERN = """
|
||||
power<
|
||||
'isinstance'
|
||||
trailer< '(' arglist< any ',' atom< '('
|
||||
args=testlist_gexp< any+ >
|
||||
')' > > ')' >
|
||||
>
|
||||
"""
|
||||
|
||||
run_order = 6
|
||||
|
||||
def transform(self, node, results):
|
||||
names_inserted = set()
|
||||
testlist = results["args"]
|
||||
args = testlist.children
|
||||
new_args = []
|
||||
iterator = enumerate(args)
|
||||
for idx, arg in iterator:
|
||||
if arg.type == token.NAME and arg.value in names_inserted:
|
||||
if idx < len(args) - 1 and args[idx + 1].type == token.COMMA:
|
||||
next(iterator)
|
||||
continue
|
||||
else:
|
||||
new_args.append(arg)
|
||||
if arg.type == token.NAME:
|
||||
names_inserted.add(arg.value)
|
||||
if new_args and new_args[-1].type == token.COMMA:
|
||||
del new_args[-1]
|
||||
if len(new_args) == 1:
|
||||
atom = testlist.parent
|
||||
new_args[0].prefix = atom.prefix
|
||||
atom.replace(new_args[0])
|
||||
else:
|
||||
args[:] = new_args
|
||||
node.changed()
|
||||
43
Lib/lib2to3/fixes/fix_itertools.py
Normal file
43
Lib/lib2to3/fixes/fix_itertools.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
""" Fixer for itertools.(imap|ifilter|izip) --> (map|filter|zip) and
|
||||
itertools.ifilterfalse --> itertools.filterfalse (bugs 2360-2363)
|
||||
|
||||
imports from itertools are fixed in fix_itertools_import.py
|
||||
|
||||
If itertools is imported as something else (ie: import itertools as it;
|
||||
it.izip(spam, eggs)) method calls will not get fixed.
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name
|
||||
|
||||
class FixItertools(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
it_funcs = "('imap'|'ifilter'|'izip'|'izip_longest'|'ifilterfalse')"
|
||||
PATTERN = """
|
||||
power< it='itertools'
|
||||
trailer<
|
||||
dot='.' func=%(it_funcs)s > trailer< '(' [any] ')' > >
|
||||
|
|
||||
power< func=%(it_funcs)s trailer< '(' [any] ')' > >
|
||||
""" %(locals())
|
||||
|
||||
# Needs to be run after fix_(map|zip|filter)
|
||||
run_order = 6
|
||||
|
||||
def transform(self, node, results):
|
||||
prefix = None
|
||||
func = results['func'][0]
|
||||
if ('it' in results and
|
||||
func.value not in ('ifilterfalse', 'izip_longest')):
|
||||
dot, it = (results['dot'], results['it'])
|
||||
# Remove the 'itertools'
|
||||
prefix = it.prefix
|
||||
it.remove()
|
||||
# Replace the node which contains ('.', 'function') with the
|
||||
# function (to be consistent with the second part of the pattern)
|
||||
dot.remove()
|
||||
func.parent.replace(func)
|
||||
|
||||
prefix = prefix or func.prefix
|
||||
func.replace(Name(func.value[1:], prefix=prefix))
|
||||
57
Lib/lib2to3/fixes/fix_itertools_imports.py
Normal file
57
Lib/lib2to3/fixes/fix_itertools_imports.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
""" Fixer for imports of itertools.(imap|ifilter|izip|ifilterfalse) """
|
||||
|
||||
# Local imports
|
||||
from lib2to3 import fixer_base
|
||||
from lib2to3.fixer_util import BlankLine, syms, token
|
||||
|
||||
|
||||
class FixItertoolsImports(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
PATTERN = """
|
||||
import_from< 'from' 'itertools' 'import' imports=any >
|
||||
""" %(locals())
|
||||
|
||||
def transform(self, node, results):
|
||||
imports = results['imports']
|
||||
if imports.type == syms.import_as_name or not imports.children:
|
||||
children = [imports]
|
||||
else:
|
||||
children = imports.children
|
||||
for child in children[::2]:
|
||||
if child.type == token.NAME:
|
||||
member = child.value
|
||||
name_node = child
|
||||
elif child.type == token.STAR:
|
||||
# Just leave the import as is.
|
||||
return
|
||||
else:
|
||||
assert child.type == syms.import_as_name
|
||||
name_node = child.children[0]
|
||||
member_name = name_node.value
|
||||
if member_name in ('imap', 'izip', 'ifilter'):
|
||||
child.value = None
|
||||
child.remove()
|
||||
elif member_name in ('ifilterfalse', 'izip_longest'):
|
||||
node.changed()
|
||||
name_node.value = ('filterfalse' if member_name[1] == 'f'
|
||||
else 'zip_longest')
|
||||
|
||||
# Make sure the import statement is still sane
|
||||
children = imports.children[:] or [imports]
|
||||
remove_comma = True
|
||||
for child in children:
|
||||
if remove_comma and child.type == token.COMMA:
|
||||
child.remove()
|
||||
else:
|
||||
remove_comma ^= True
|
||||
|
||||
while children and children[-1].type == token.COMMA:
|
||||
children.pop().remove()
|
||||
|
||||
# If there are no imports left, just get rid of the entire statement
|
||||
if (not (imports.children or getattr(imports, 'value', None)) or
|
||||
imports.parent is None):
|
||||
p = node.prefix
|
||||
node = BlankLine()
|
||||
node.prefix = p
|
||||
return node
|
||||
19
Lib/lib2to3/fixes/fix_long.py
Normal file
19
Lib/lib2to3/fixes/fix_long.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Copyright 2006 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Fixer that turns 'long' into 'int' everywhere.
|
||||
"""
|
||||
|
||||
# Local imports
|
||||
from lib2to3 import fixer_base
|
||||
from lib2to3.fixer_util import is_probably_builtin
|
||||
|
||||
|
||||
class FixLong(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
PATTERN = "'long'"
|
||||
|
||||
def transform(self, node, results):
|
||||
if is_probably_builtin(node):
|
||||
node.value = "int"
|
||||
node.changed()
|
||||
110
Lib/lib2to3/fixes/fix_map.py
Normal file
110
Lib/lib2to3/fixes/fix_map.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
# 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, ArgList, Call, ListComp, in_special_context
|
||||
from ..pygram import python_symbols as syms
|
||||
from ..pytree import Node
|
||||
|
||||
|
||||
class FixMap(fixer_base.ConditionalFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
map_none=power<
|
||||
'map'
|
||||
trailer< '(' arglist< 'None' ',' arg=any [','] > ')' >
|
||||
[extra_trailers=trailer*]
|
||||
>
|
||||
|
|
||||
map_lambda=power<
|
||||
'map'
|
||||
trailer<
|
||||
'('
|
||||
arglist<
|
||||
lambdef< 'lambda'
|
||||
(fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any
|
||||
>
|
||||
','
|
||||
it=any
|
||||
>
|
||||
')'
|
||||
>
|
||||
[extra_trailers=trailer*]
|
||||
>
|
||||
|
|
||||
power<
|
||||
'map' args=trailer< '(' [any] ')' >
|
||||
[extra_trailers=trailer*]
|
||||
>
|
||||
"""
|
||||
|
||||
skip_on = 'future_builtins.map'
|
||||
|
||||
def transform(self, node, results):
|
||||
if self.should_skip(node):
|
||||
return
|
||||
|
||||
trailers = []
|
||||
if 'extra_trailers' in results:
|
||||
for t in results['extra_trailers']:
|
||||
trailers.append(t.clone())
|
||||
|
||||
if node.parent.type == syms.simple_stmt:
|
||||
self.warning(node, "You should use a for loop here")
|
||||
new = node.clone()
|
||||
new.prefix = ""
|
||||
new = Call(Name("list"), [new])
|
||||
elif "map_lambda" in results:
|
||||
new = ListComp(results["xp"].clone(),
|
||||
results["fp"].clone(),
|
||||
results["it"].clone())
|
||||
new = Node(syms.power, [new] + trailers, prefix="")
|
||||
|
||||
else:
|
||||
if "map_none" in results:
|
||||
new = results["arg"].clone()
|
||||
new.prefix = ""
|
||||
else:
|
||||
if "args" in results:
|
||||
args = results["args"]
|
||||
if args.type == syms.trailer and \
|
||||
args.children[1].type == syms.arglist and \
|
||||
args.children[1].children[0].type == token.NAME and \
|
||||
args.children[1].children[0].value == "None":
|
||||
self.warning(node, "cannot convert map(None, ...) "
|
||||
"with multiple arguments because map() "
|
||||
"now truncates to the shortest sequence")
|
||||
return
|
||||
|
||||
new = Node(syms.power, [Name("map"), args.clone()])
|
||||
new.prefix = ""
|
||||
|
||||
if in_special_context(node):
|
||||
return None
|
||||
|
||||
new = Node(syms.power, [Name("list"), ArgList([new])] + trailers)
|
||||
new.prefix = ""
|
||||
|
||||
new.prefix = node.prefix
|
||||
return new
|
||||
228
Lib/lib2to3/fixes/fix_metaclass.py
Normal file
228
Lib/lib2to3/fixes/fix_metaclass.py
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
"""Fixer for __metaclass__ = X -> (metaclass=X) methods.
|
||||
|
||||
The various forms of classef (inherits nothing, inherits once, inherints
|
||||
many) don't parse the same in the CST so we look at ALL classes for
|
||||
a __metaclass__ and if we find one normalize the inherits to all be
|
||||
an arglist.
|
||||
|
||||
For one-liner classes ('class X: pass') there is no indent/dedent so
|
||||
we normalize those into having a suite.
|
||||
|
||||
Moving the __metaclass__ into the classdef can also cause the class
|
||||
body to be empty so there is some special casing for that as well.
|
||||
|
||||
This fixer also tries very hard to keep original indenting and spacing
|
||||
in all those corner cases.
|
||||
|
||||
"""
|
||||
# Author: Jack Diederich
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..pygram import token
|
||||
from ..fixer_util import syms, Node, Leaf
|
||||
|
||||
|
||||
def has_metaclass(parent):
|
||||
""" we have to check the cls_node without changing it.
|
||||
There are two possibilities:
|
||||
1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta')
|
||||
2) clsdef => simple_stmt => expr_stmt => Leaf('__meta')
|
||||
"""
|
||||
for node in parent.children:
|
||||
if node.type == syms.suite:
|
||||
return has_metaclass(node)
|
||||
elif node.type == syms.simple_stmt and node.children:
|
||||
expr_node = node.children[0]
|
||||
if expr_node.type == syms.expr_stmt and expr_node.children:
|
||||
left_side = expr_node.children[0]
|
||||
if isinstance(left_side, Leaf) and \
|
||||
left_side.value == '__metaclass__':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def fixup_parse_tree(cls_node):
|
||||
""" one-line classes don't get a suite in the parse tree so we add
|
||||
one to normalize the tree
|
||||
"""
|
||||
for node in cls_node.children:
|
||||
if node.type == syms.suite:
|
||||
# already in the preferred format, do nothing
|
||||
return
|
||||
|
||||
# !%@#! oneliners have no suite node, we have to fake one up
|
||||
for i, node in enumerate(cls_node.children):
|
||||
if node.type == token.COLON:
|
||||
break
|
||||
else:
|
||||
raise ValueError("No class suite and no ':'!")
|
||||
|
||||
# move everything into a suite node
|
||||
suite = Node(syms.suite, [])
|
||||
while cls_node.children[i+1:]:
|
||||
move_node = cls_node.children[i+1]
|
||||
suite.append_child(move_node.clone())
|
||||
move_node.remove()
|
||||
cls_node.append_child(suite)
|
||||
node = suite
|
||||
|
||||
|
||||
def fixup_simple_stmt(parent, i, stmt_node):
|
||||
""" if there is a semi-colon all the parts count as part of the same
|
||||
simple_stmt. We just want the __metaclass__ part so we move
|
||||
everything after the semi-colon into its own simple_stmt node
|
||||
"""
|
||||
for semi_ind, node in enumerate(stmt_node.children):
|
||||
if node.type == token.SEMI: # *sigh*
|
||||
break
|
||||
else:
|
||||
return
|
||||
|
||||
node.remove() # kill the semicolon
|
||||
new_expr = Node(syms.expr_stmt, [])
|
||||
new_stmt = Node(syms.simple_stmt, [new_expr])
|
||||
while stmt_node.children[semi_ind:]:
|
||||
move_node = stmt_node.children[semi_ind]
|
||||
new_expr.append_child(move_node.clone())
|
||||
move_node.remove()
|
||||
parent.insert_child(i, new_stmt)
|
||||
new_leaf1 = new_stmt.children[0].children[0]
|
||||
old_leaf1 = stmt_node.children[0].children[0]
|
||||
new_leaf1.prefix = old_leaf1.prefix
|
||||
|
||||
|
||||
def remove_trailing_newline(node):
|
||||
if node.children and node.children[-1].type == token.NEWLINE:
|
||||
node.children[-1].remove()
|
||||
|
||||
|
||||
def find_metas(cls_node):
|
||||
# find the suite node (Mmm, sweet nodes)
|
||||
for node in cls_node.children:
|
||||
if node.type == syms.suite:
|
||||
break
|
||||
else:
|
||||
raise ValueError("No class suite!")
|
||||
|
||||
# look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ]
|
||||
for i, simple_node in list(enumerate(node.children)):
|
||||
if simple_node.type == syms.simple_stmt and simple_node.children:
|
||||
expr_node = simple_node.children[0]
|
||||
if expr_node.type == syms.expr_stmt and expr_node.children:
|
||||
# Check if the expr_node is a simple assignment.
|
||||
left_node = expr_node.children[0]
|
||||
if isinstance(left_node, Leaf) and \
|
||||
left_node.value == '__metaclass__':
|
||||
# We found an assignment to __metaclass__.
|
||||
fixup_simple_stmt(node, i, simple_node)
|
||||
remove_trailing_newline(simple_node)
|
||||
yield (node, i, simple_node)
|
||||
|
||||
|
||||
def fixup_indent(suite):
|
||||
""" If an INDENT is followed by a thing with a prefix then nuke the prefix
|
||||
Otherwise we get in trouble when removing __metaclass__ at suite start
|
||||
"""
|
||||
kids = suite.children[::-1]
|
||||
# find the first indent
|
||||
while kids:
|
||||
node = kids.pop()
|
||||
if node.type == token.INDENT:
|
||||
break
|
||||
|
||||
# find the first Leaf
|
||||
while kids:
|
||||
node = kids.pop()
|
||||
if isinstance(node, Leaf) and node.type != token.DEDENT:
|
||||
if node.prefix:
|
||||
node.prefix = ''
|
||||
return
|
||||
else:
|
||||
kids.extend(node.children[::-1])
|
||||
|
||||
|
||||
class FixMetaclass(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
|
||||
PATTERN = """
|
||||
classdef<any*>
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
if not has_metaclass(node):
|
||||
return
|
||||
|
||||
fixup_parse_tree(node)
|
||||
|
||||
# find metaclasses, keep the last one
|
||||
last_metaclass = None
|
||||
for suite, i, stmt in find_metas(node):
|
||||
last_metaclass = stmt
|
||||
stmt.remove()
|
||||
|
||||
text_type = node.children[0].type # always Leaf(nnn, 'class')
|
||||
|
||||
# figure out what kind of classdef we have
|
||||
if len(node.children) == 7:
|
||||
# Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite])
|
||||
# 0 1 2 3 4 5 6
|
||||
if node.children[3].type == syms.arglist:
|
||||
arglist = node.children[3]
|
||||
# Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite])
|
||||
else:
|
||||
parent = node.children[3].clone()
|
||||
arglist = Node(syms.arglist, [parent])
|
||||
node.set_child(3, arglist)
|
||||
elif len(node.children) == 6:
|
||||
# Node(classdef, ['class', 'name', '(', ')', ':', suite])
|
||||
# 0 1 2 3 4 5
|
||||
arglist = Node(syms.arglist, [])
|
||||
node.insert_child(3, arglist)
|
||||
elif len(node.children) == 4:
|
||||
# Node(classdef, ['class', 'name', ':', suite])
|
||||
# 0 1 2 3
|
||||
arglist = Node(syms.arglist, [])
|
||||
node.insert_child(2, Leaf(token.RPAR, ')'))
|
||||
node.insert_child(2, arglist)
|
||||
node.insert_child(2, Leaf(token.LPAR, '('))
|
||||
else:
|
||||
raise ValueError("Unexpected class definition")
|
||||
|
||||
# now stick the metaclass in the arglist
|
||||
meta_txt = last_metaclass.children[0].children[0]
|
||||
meta_txt.value = 'metaclass'
|
||||
orig_meta_prefix = meta_txt.prefix
|
||||
|
||||
if arglist.children:
|
||||
arglist.append_child(Leaf(token.COMMA, ','))
|
||||
meta_txt.prefix = ' '
|
||||
else:
|
||||
meta_txt.prefix = ''
|
||||
|
||||
# compact the expression "metaclass = Meta" -> "metaclass=Meta"
|
||||
expr_stmt = last_metaclass.children[0]
|
||||
assert expr_stmt.type == syms.expr_stmt
|
||||
expr_stmt.children[1].prefix = ''
|
||||
expr_stmt.children[2].prefix = ''
|
||||
|
||||
arglist.append_child(last_metaclass)
|
||||
|
||||
fixup_indent(suite)
|
||||
|
||||
# check for empty suite
|
||||
if not suite.children:
|
||||
# one-liner that was just __metaclass_
|
||||
suite.remove()
|
||||
pass_leaf = Leaf(text_type, 'pass')
|
||||
pass_leaf.prefix = orig_meta_prefix
|
||||
node.append_child(pass_leaf)
|
||||
node.append_child(Leaf(token.NEWLINE, '\n'))
|
||||
|
||||
elif len(suite.children) > 1 and \
|
||||
(suite.children[-2].type == token.INDENT and
|
||||
suite.children[-1].type == token.DEDENT):
|
||||
# there was only one line in the class body and it was __metaclass__
|
||||
pass_leaf = Leaf(text_type, 'pass')
|
||||
suite.insert_child(-1, pass_leaf)
|
||||
suite.insert_child(-1, Leaf(token.NEWLINE, '\n'))
|
||||
24
Lib/lib2to3/fixes/fix_methodattrs.py
Normal file
24
Lib/lib2to3/fixes/fix_methodattrs.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
"""Fix bound method attributes (method.im_? -> method.__?__).
|
||||
"""
|
||||
# Author: Christian Heimes
|
||||
|
||||
# Local imports
|
||||
from .. import fixer_base
|
||||
from ..fixer_util import Name
|
||||
|
||||
MAP = {
|
||||
"im_func" : "__func__",
|
||||
"im_self" : "__self__",
|
||||
"im_class" : "__self__.__class__"
|
||||
}
|
||||
|
||||
class FixMethodattrs(fixer_base.BaseFix):
|
||||
BM_compatible = True
|
||||
PATTERN = """
|
||||
power< any+ trailer< '.' attr=('im_func' | 'im_self' | 'im_class') > any* >
|
||||
"""
|
||||
|
||||
def transform(self, node, results):
|
||||
attr = results["attr"][0]
|
||||
new = MAP[attr.value]
|
||||
attr.replace(Name(new, prefix=attr.prefix))
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue