More Python3 compatability. Remove duplicate disassembly code and

get it from Python's standard library instead.
This commit is contained in:
rocky
2015-12-12 08:37:20 -05:00
parent 00d17461fc
commit 003d485814
9 changed files with 106 additions and 254 deletions

View File

@@ -5,7 +5,12 @@ from __future__ import print_function
import uncompyle6 import uncompyle6
from uncompyle6 import uncompyle, walker, verify, magics from uncompyle6 import uncompyle, walker, verify, magics
from uncompyle6.spark import GenericASTTraversal, GenericASTTraversalPruningException from uncompyle6.spark import GenericASTTraversal, GenericASTTraversalPruningException
import sys, inspect, types, cStringIO import sys, inspect, types
if (sys.version_info > (3, 0)):
from io import StringIO
else:
from StringIO import StringIO
from collections import namedtuple from collections import namedtuple
NodeInfo = namedtuple("NodeInfo", "node start finish") NodeInfo = namedtuple("NodeInfo", "node start finish")
@@ -120,7 +125,7 @@ class FindWalker(walker.Walker, object):
self.pending_newlines = 0 self.pending_newlines = 0
self.__params = { self.__params = {
'_globals': {}, '_globals': {},
'f': cStringIO.StringIO(), 'f': StringIO(),
'indent': indent, 'indent': indent,
'isLambda': isLambda, 'isLambda': isLambda,
} }

View File

@@ -100,7 +100,7 @@ def uncompyle(version, co, out=None, showasm=0, showast=0):
file=__real_out) file=__real_out)
# diff scanner # diff scanner
if version == 2.7: if version == 2.7:
import scanner27 as scan import uncompyle6.scanner27 as scan
scanner = scan.Scanner27() scanner = scan.Scanner27()
elif version == 2.6: elif version == 2.6:
import scanner26 as scan import scanner26 as scan

View File

@@ -1,191 +1,18 @@
from __future__ import print_function
"""Disassembler of Python byte code into mnemonics.""" """Disassembler of Python byte code into mnemonics."""
import sys import marshal, pickle, sys, types
import types
from struct import unpack import dis as Mdis
import marshal, pickle
from struct import unpack
_have_code = (types.MethodType, types.FunctionType, types.CodeType, types.ClassType, type)
internStrings = [] internStrings = []
def dis(x=None): disco = Mdis.disassemble
"""Disassemble classes, methods, functions, or code.
With no argument, disassemble the last traceback.
"""
if x is None:
distb()
return
if isinstance(x, types.InstanceType):
x = x.__class__
if hasattr(x, 'im_func'):
x = x.im_func
if hasattr(x, 'func_code'):
x = x.func_code
if hasattr(x, '__dict__'):
items = x.__dict__.items()
items.sort()
for name, x1 in items:
if isinstance(x1, _have_code):
print "Disassembly of %s:" % name
try:
dis(x1)
except TypeError, msg:
print "Sorry:", msg
print
elif hasattr(x, 'co_code'):
disassemble(x)
elif isinstance(x, str):
disassemble_string(x)
else:
raise (TypeError,
"don't know how to disassemble %s objects" % type(x).__name__)
def distb(tb=None):
"""Disassemble a traceback (default: last traceback)."""
if tb is None:
try:
tb = sys.last_traceback
except AttributeError:
raise(RuntimeError, "no last traceback to disassemble")
while tb.tb_next: tb = tb.tb_next
disassemble(tb.tb_frame.f_code, tb.tb_lasti)
def disassemble(co, lasti=-1):
"""Disassemble a code object."""
code = co.co_code
labels = findlabels(code)
linestarts = dict(findlinestarts(co))
n = len(code)
i = 0
extended_arg = 0
free = None
while i < n:
c = code[i]
op = ord(c)
if i in linestarts:
if i > 0:
print
print "%3d" % linestarts[i],
else:
print ' ',
if i == lasti: print '-->',
else: print ' ',
if i in labels: print '>>',
else: print ' ',
print repr(i).rjust(4),
print opname[op].ljust(20),
i = i+1
if op >= HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
extended_arg = 0
i = i+2
if op == EXTENDED_ARG:
extended_arg = oparg*65536L
print repr(oparg).rjust(5),
if op in hasconst:
print '(' + repr(co.co_consts[oparg]) + ')',
elif op in hasname:
print '(' + co.co_names[oparg] + ')',
elif op in hasjrel:
print '(to ' + repr(i + oparg) + ')',
elif op in haslocal:
print '(' + co.co_varnames[oparg] + ')',
elif op in hascompare:
print '(' + cmp_op[oparg] + ')',
elif op in hasfree:
if free is None:
free = co.co_cellvars + co.co_freevars
print '(' + free[oparg] + ')',
print
def disassemble_string(code, lasti=-1, varnames=None, names=None,
constants=None):
labels = findlabels(code)
n = len(code)
i = 0
while i < n:
c = code[i]
op = ord(c)
if i == lasti: print '-->',
else: print ' ',
if i in labels: print '>>',
else: print ' ',
print repr(i).rjust(4),
print opname[op].ljust(15),
i = i+1
if op >= HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i+1])*256
i = i+2
print repr(oparg).rjust(5),
if op in hasconst:
if constants:
print '(' + repr(constants[oparg]) + ')',
else:
print '(%d)' % oparg,
elif op in hasname:
if names is not None:
print '(' + names[oparg] + ')',
else:
print '(%d)'%oparg,
elif op in hasjrel:
print '(to ' + repr(i + oparg) + ')',
elif op in haslocal:
if varnames:
print '(' + varnames[oparg] + ')',
else:
print '(%d)' % oparg,
elif op in hascompare:
print '(' + cmp_op[oparg] + ')',
print
disco = disassemble
# XXX For backwards compatibility # XXX For backwards compatibility
def findlabels(code):
"""Detect all offsets in a byte code which are jump targets.
Return the list of offsets.
"""
labels = []
n = len(code)
i = 0
while i < n:
c = code[i]
op = ord(c)
i = i+1
if op >= HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i+1])*256
i = i+2
label = -1
if op in hasjrel:
label = i+oparg
elif op in hasjabs:
label = oparg
if label >= 0:
if label not in labels:
labels.append(label)
return labels
def findlinestarts(code):
"""Find the offsets in a byte code which are start of lines in the source.
Generate pairs (offset, lineno) as described in Python/compile.c.
"""
byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
line_increments = [ord(c) for c in code.co_lnotab[1::2]]
lastlineno = None
lineno = code.co_firstlineno
addr = 0
for byte_incr, line_incr in zip(byte_increments, line_increments):
if byte_incr:
if lineno != lastlineno:
yield (addr, lineno)
lastlineno = lineno
addr += byte_incr
lineno += line_incr
if lineno != lastlineno:
yield (addr, lineno)
def marshalLoad(fp): def marshalLoad(fp):
global internStrings global internStrings
internStrings = [] internStrings = []
@@ -223,7 +50,7 @@ def load(fp):
elif marshalType == '.': elif marshalType == '.':
return Ellipsis return Ellipsis
elif marshalType == '0': elif marshalType == '0':
raise KeyError, marshalType raise KeyError(marshalType)
return None return None
elif marshalType == 'N': elif marshalType == 'N':
return None return None
@@ -244,20 +71,20 @@ def load(fp):
elif marshalType == 'I': elif marshalType == 'I':
return unpack('q', fp.read(8))[0] return unpack('q', fp.read(8))[0]
elif marshalType == 'x': elif marshalType == 'x':
raise KeyError, marshalType raise KeyError(marshalType)
return None return None
elif marshalType == 'y': elif marshalType == 'y':
raise KeyError, marshalType raise KeyError(marshalType)
return None return None
elif marshalType == 'l': elif marshalType == 'l':
n = unpack('i', fp.read(4))[0] n = unpack('i', fp.read(4))[0]
if n == 0: if n == 0:
return long(0) return long(0)
size = abs(n); size = abs(n)
d = long(0) d = long(0)
for j in range(0, size): for j in range(0, size):
md = int(unpack('h', fp.read(2))[0]) md = int(unpack('h', fp.read(2))[0])
d += md << j*15; d += md << j*15
if n < 0: if n < 0:
return long(d*-1) return long(d*-1)
return d return d
@@ -286,16 +113,16 @@ def load(fp):
tuplesize -= 1 tuplesize -= 1
return ret return ret
elif marshalType == '[': elif marshalType == '[':
raise KeyError, marshalType raise KeyError(marshalType)
return None return None
elif marshalType == '{': elif marshalType == '{':
raise KeyError, marshalType raise KeyError(marshalType)
return None return None
elif marshalType in ['<', '>']: elif marshalType in ['<', '>']:
raise KeyError, marshalType raise KeyError(marshalType)
return None return None
else: else:
sys.stderr.write("Unkown type %i (hex %x)\n" % (ord(marshalType), ord(marshalType))) sys.stderr.write("Unknown type %i (hex %x)\n" % (ord(marshalType), ord(marshalType)))
def _test(): def _test():
"""Simple test program to disassemble a file.""" """Simple test program to disassemble a file."""
@@ -318,7 +145,7 @@ def _test():
else: else:
fn = "<stdin>" fn = "<stdin>"
code = compile(source, fn, "exec") code = compile(source, fn, "exec")
dis(code) Mdis.dis(code)
if __name__ == "__main__": if __name__ == "__main__":
_test() _test()

View File

@@ -9,13 +9,18 @@ from __future__ import print_function
__all__ = ['Token', 'Scanner', 'Code'] __all__ = ['Token', 'Scanner', 'Code']
import types import sys, types
from collections import namedtuple from collections import namedtuple
from array import array from array import array
from operator import itemgetter from operator import itemgetter
if (sys.version_info > (3, 0)):
intern = sys.intern
import uncompyle6
from uncompyle6.opcodes import opcode_25, opcode_26, opcode_27 from uncompyle6.opcodes import opcode_25, opcode_26, opcode_27
class Token: class Token:
''' '''
Class representing a byte-code token. Class representing a byte-code token.
@@ -84,7 +89,7 @@ class Scanner(object):
self.out = out self.out = out
def setTokenClass(self, tokenClass): def setTokenClass(self, tokenClass):
assert isinstance(tokenClass, types.ClassType) # assert isinstance(tokenClass, types.ClassType)
self.Token = tokenClass self.Token = tokenClass
return self.Token return self.Token

View File

@@ -13,7 +13,7 @@ from operator import itemgetter
from struct import * from struct import *
from uncompyle6.opcodes.opcode_25 import * from uncompyle6.opcodes.opcode_25 import *
import disas as dis import dis
import scanner as scan import scanner as scan
class Scanner25(scan.Scanner): class Scanner25(scan.Scanner):

View File

@@ -13,7 +13,7 @@ from operator import itemgetter
from struct import * from struct import *
from uncompyle6.opcodes.opcode_26 import * from uncompyle6.opcodes.opcode_26 import *
import disas as dis import dis
import scanner as scan import scanner as scan
class Scanner26(scan.Scanner): class Scanner26(scan.Scanner):

View File

@@ -1,3 +1,5 @@
from __future__ import print_function
''' '''
Copyright (c) 1999 John Aycock Copyright (c) 1999 John Aycock
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
@@ -6,14 +8,13 @@
See main module for license. See main module for license.
''' '''
import types import dis, types
from collections import namedtuple from collections import namedtuple
from array import array from array import array
from operator import itemgetter from operator import itemgetter
from uncompyle6.opcodes.opcode_27 import * from uncompyle6.opcodes.opcode_27 import *
import disas as dis import uncompyle6.scanner as scan
import scanner as scan
class Scanner27(scan.Scanner): class Scanner27(scan.Scanner):
def __init__(self): def __init__(self):
@@ -121,7 +122,7 @@ class Scanner27(scan.Scanner):
oparg = self.get_argument(offset) + extended_arg oparg = self.get_argument(offset) + extended_arg
extended_arg = 0 extended_arg = 0
if op == EXTENDED_ARG: if op == EXTENDED_ARG:
extended_arg = oparg * 65536L extended_arg = oparg * 65536
continue continue
if op in hasconst: if op in hasconst:
const = co.co_consts[oparg] const = co.co_consts[oparg]
@@ -197,8 +198,8 @@ class Scanner27(scan.Scanner):
if self.showasm: if self.showasm:
out = self.out # shortcut out = self.out # shortcut
for t in rv: for t in rv:
print >>out, t print(t, file=out)
print >>out print(file=out)
return rv, customize return rv, customize
def op_size(self, op): def op_size(self, op):

View File

@@ -1,18 +1,25 @@
from __future__ import print_function
# #
# (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# #
# byte-code verifier for uncompyle # byte-code verifier for uncompyle
# #
import types import dis, operator, sys, types
import operator
import dis import uncompyle6
import uncompyle2, scanner import uncompyle6.scanner as scanner
if (sys.version_info > (3, 0)):
truediv = operator.truediv
else:
truediv = operator.div
BIN_OP_FUNCS = { BIN_OP_FUNCS = {
'BINARY_POWER': operator.pow, 'BINARY_POWER': operator.pow,
'BINARY_MULTIPLY': operator.mul, 'BINARY_MULTIPLY': operator.mul,
'BINARY_DIVIDE': operator.div, 'BINARY_DIVIDE': truediv,
'BINARY_FLOOR_DIVIDE': operator.floordiv, 'BINARY_FLOOR_DIVIDE': operator.floordiv,
'BINARY_TRUE_DIVIDE': operator.truediv, 'BINARY_TRUE_DIVIDE': operator.truediv,
'BINARY_MODULO' : operator.mod, 'BINARY_MODULO' : operator.mod,
@@ -61,8 +68,8 @@ class CmpErrorConstsLen(VerifyCmpError):
def __str__(self): def __str__(self):
return 'Consts length differs in %s:\n\n%i:\t%s\n\n%i:\t%s\n\n' % \ return 'Consts length differs in %s:\n\n%i:\t%s\n\n%i:\t%s\n\n' % \
(repr(self.name), (repr(self.name),
len(self.consts[0]), `self.consts[0]`, len(self.consts[0]), repr(self.consts[0]),
len(self.consts[1]), `self.consts[1]`) len(self.consts[1]), repr(self.consts[1]))
class CmpErrorCode(VerifyCmpError): class CmpErrorCode(VerifyCmpError):
"""Exception to be raised when code differs.""" """Exception to be raised when code differs."""
@@ -75,9 +82,9 @@ class CmpErrorCode(VerifyCmpError):
def __str__(self): def __str__(self):
s = reduce(lambda s,t: "%s%-37s\t%-37s\n" % (s, t[0], t[1]), s = reduce(lambda s,t: "%s%-37s\t%-37s\n" % (s, t[0], t[1]),
map(lambda a,b: (a,b), list(map(lambda a,b: (a,b),
self.tokens[0], self.tokens[0],
self.tokens[1]), self.tokens[1])),
'Code differs in %s\n' % str(self.name)) 'Code differs in %s\n' % str(self.name))
return ('Code differs in %s at offset %s [%s] != [%s]\n\n' % \ return ('Code differs in %s at offset %s [%s] != [%s]\n\n' % \
(repr(self.name), self.index, (repr(self.name), self.index,
@@ -91,9 +98,9 @@ class CmpErrorCodeLen(VerifyCmpError):
def __str__(self): def __str__(self):
return reduce(lambda s,t: "%s%-37s\t%-37s\n" % (s, t[0], t[1]), return reduce(lambda s,t: "%s%-37s\t%-37s\n" % (s, t[0], t[1]),
map(lambda a,b: (a,b), list(map(lambda a,b: (a,b),
self.tokens[0], self.tokens[0],
self.tokens[1]), self.tokens[1])),
'Code len differs in %s\n' % str(self.name)) 'Code len differs in %s\n' % str(self.name))
class CmpErrorMember(VerifyCmpError): class CmpErrorMember(VerifyCmpError):
@@ -149,7 +156,7 @@ def cmp_code_objects(version, code_obj1, code_obj2, name=''):
pass pass
if isinstance(code_obj1, object): if isinstance(code_obj1, object):
members = filter(lambda x: x.startswith('co_'), dir(code_obj1)) members = [x for x in dir(code_obj1) if x.startswith('co_')]
else: else:
members = dir(code_obj1); members = dir(code_obj1);
members.sort(); #members.reverse() members.sort(); #members.reverse()
@@ -311,7 +318,7 @@ class Token(scanner.Token):
return 0 return 0
if t == 'JUMP_IF_FALSE_OR_POP' and o.type == 'POP_JUMP_IF_FALSE': if t == 'JUMP_IF_FALSE_OR_POP' and o.type == 'POP_JUMP_IF_FALSE':
return 0 return 0
if t in JUMP_OPs: if JUMP_OPs and t in JUMP_OPs:
# ignore offset # ignore offset
return cmp(t, o.type) return cmp(t, o.type)
return cmp(t, o.type) or cmp(self.pattr, o.pattr) return cmp(t, o.type) or cmp(self.pattr, o.pattr)
@@ -338,6 +345,8 @@ def compare_files(pyc_filename1, pyc_filename2):
if __name__ == '__main__': if __name__ == '__main__':
t1 = Token('LOAD_CONST', None, 'code_object _expandLang', 52) t1 = Token('LOAD_CONST', None, 'code_object _expandLang', 52)
t2 = Token('LOAD_CONST', -421, 'code_object _expandLang', 55) t2 = Token('LOAD_CONST', -421, 'code_object _expandLang', 55)
print `t1` print(repr(t1))
print `t2` print(repr(t2))
print cmp(t1, t2), cmp(t1.type, t2.type), cmp(t1.attr, t2.attr)
if (sys.version_info < (3, 0)):
print(cmp(t1, t2), cmp(t1.type, t2.type), cmp(t1.attr, t2.attr))

View File

@@ -43,23 +43,28 @@ from __future__ import print_function
makes the engine walk down to N[C] before evaluating the escape code. makes the engine walk down to N[C] before evaluating the escape code.
''' '''
try: import sys, re
if (sys.version_info > (3, 0)):
from io import StringIO
import uncompyle6
from .spark import GenericASTTraversal
from .parser import AST
from .scanner import Token, Code
minint = -sys.maxsize-1
maxint = sys.maxsize
else:
from StringIO import StringIO from StringIO import StringIO
from spark import GenericASTTraversal from spark import GenericASTTraversal
from parser import AST from parser import AST
from scanner import Token, Code from scanner import Token, Code
except ImportError: minint = -sys.maxint-1
from io import StringIO maxint = sys.maxint
from .spark import GenericASTTraversal
from .parser import AST
from .scanner import Token, Code
import sys, re
from types import CodeType from types import CodeType
import parser import parser
minint = -sys.maxint-1
# Some ASTs used for comparing code fragments (like 'return None' at # Some ASTs used for comparing code fragments (like 'return None' at
# the end of functions). # the end of functions).
@@ -114,7 +119,7 @@ TABLE_R = {
'DELETE_SLICE+2': ( '%|del %c[:%c]\n', 0, 1 ), 'DELETE_SLICE+2': ( '%|del %c[:%c]\n', 0, 1 ),
'DELETE_SLICE+3': ( '%|del %c[%c:%c]\n', 0, 1, 2 ), 'DELETE_SLICE+3': ( '%|del %c[%c:%c]\n', 0, 1, 2 ),
'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ), 'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ),
# 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,sys.maxint,', ') ), # 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,maxint,', ') ),
} }
TABLE_R0 = { TABLE_R0 = {
# 'BUILD_LIST': ( '[%C]', (0,-1,', ') ), # 'BUILD_LIST': ( '[%C]', (0,-1,', ') ),
@@ -183,9 +188,9 @@ TABLE_DIRECT = {
'STORE_NAME': ( '%{pattr}', ), 'STORE_NAME': ( '%{pattr}', ),
'STORE_GLOBAL': ( '%{pattr}', ), 'STORE_GLOBAL': ( '%{pattr}', ),
'STORE_DEREF': ( '%{pattr}', ), 'STORE_DEREF': ( '%{pattr}', ),
'unpack': ( '%C%,', (1, sys.maxint, ', ') ), 'unpack': ( '%C%,', (1, maxint, ', ') ),
'unpack_w_parens': ( '(%C%,)', (1, sys.maxint, ', ') ), 'unpack_w_parens': ( '(%C%,)', (1, maxint, ', ') ),
'unpack_list': ( '[%C]', (1, sys.maxint, ', ') ), 'unpack_list': ( '[%C]', (1, maxint, ', ') ),
'build_tuple2': ( '%P', (0,-1,', ', 100) ), 'build_tuple2': ( '%P', (0,-1,', ', 100) ),
#'list_compr': ( '[ %c ]', -2), # handled by n_list_compr #'list_compr': ( '[ %c ]', -2), # handled by n_list_compr
@@ -232,7 +237,7 @@ TABLE_DIRECT = {
'classdefdeco': ( '%c', 0), 'classdefdeco': ( '%c', 0),
'classdefdeco1': ( '\n\n%|@%c%c', 0, 1), 'classdefdeco1': ( '\n\n%|@%c%c', 0, 1),
'kwarg': ( '%[0]{pattr}=%c', 1), 'kwarg': ( '%[0]{pattr}=%c', 1),
'importlist2': ( '%C', (0, sys.maxint, ', ') ), 'importlist2': ( '%C', (0, maxint, ', ') ),
'assert': ( '%|assert %c\n' , 0 ), 'assert': ( '%|assert %c\n' , 0 ),
'assert2': ( '%|assert %c, %c\n' , 0, 3 ), 'assert2': ( '%|assert %c, %c\n' , 0, 3 ),
@@ -294,7 +299,7 @@ TABLE_DIRECT = {
'except': ( '%|except:\n%+%c%-', 3 ), 'except': ( '%|except:\n%+%c%-', 3 ),
'except_cond1': ( '%|except %c:\n', 1 ), 'except_cond1': ( '%|except %c:\n', 1 ),
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
'except_suite': ( '%+%c%-%C', 0, (1, sys.maxint, '') ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ),
'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ), 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ),
'withstmt': ( '%|with %c:\n%+%c%-', 0, 3), 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 3), 'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 3),
@@ -302,7 +307,7 @@ TABLE_DIRECT = {
'STORE_FAST': ( '%{pattr}', ), 'STORE_FAST': ( '%{pattr}', ),
'kv': ( '%c: %c', 3, 1 ), 'kv': ( '%c: %c', 3, 1 ),
'kv2': ( '%c: %c', 1, 2 ), 'kv2': ( '%c: %c', 1, 2 ),
'mapexpr': ( '{%[1]C}', (0,sys.maxint,', ') ), 'mapexpr': ( '{%[1]C}', (0,maxint,', ') ),
## ##
## Python 2.5 Additions ## Python 2.5 Additions
@@ -583,7 +588,7 @@ class Walker(GenericASTTraversal, object):
#Restore escaped backslashes #Restore escaped backslashes
docstring = docstring.replace('\t', '\\\\') docstring = docstring.replace('\t', '\\\\')
lines = docstring.split('\n') lines = docstring.split('\n')
calculate_indent = sys.maxint calculate_indent = maxint
for line in lines[1:]: for line in lines[1:]:
stripped = line.lstrip() stripped = line.lstrip()
if len(stripped) > 0: if len(stripped) > 0:
@@ -591,7 +596,7 @@ class Walker(GenericASTTraversal, object):
calculate_indent = min(calculate_indent, len(lines[-1]) - len(lines[-1].lstrip())) calculate_indent = min(calculate_indent, len(lines[-1]) - len(lines[-1].lstrip()))
# Remove indentation (first line is special): # Remove indentation (first line is special):
trimmed = [lines[0]] trimmed = [lines[0]]
if calculate_indent < sys.maxint: if calculate_indent < maxint:
trimmed += [line[calculate_indent:] for line in lines[1:]] trimmed += [line[calculate_indent:] for line in lines[1:]]
self.write(quote) self.write(quote)