109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh#! /usr/bin/env python 209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh# Released to the public domain, by Tim Peters, 03 October 2000. 409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh"""reindent [-d][-r][-v] [ path ... ] 609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh-d (--dryrun) Dry run. Analyze, but don't make any changes to, files. 809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh-r (--recurse) Recurse. Search for all .py files in subdirectories too. 909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh-n (--nobackup) No backup. Does not make a ".bak" file before reindenting. 1009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh-v (--verbose) Verbose. Print informative msgs; else no output. 1109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh-h (--help) Help. Print this usage information and exit. 1209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 1309a025e087fa754b633ebc499d5c96d4e0f844b0mblighChange Python (.py) files to use 4-space indents and no hard tab characters. 1409a025e087fa754b633ebc499d5c96d4e0f844b0mblighAlso trim excess spaces and tabs from ends of lines, and remove empty lines 1509a025e087fa754b633ebc499d5c96d4e0f844b0mblighat the end of files. Also ensure the last line ends with a newline. 1609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 1709a025e087fa754b633ebc499d5c96d4e0f844b0mblighIf no paths are given on the command line, reindent operates as a filter, 1809a025e087fa754b633ebc499d5c96d4e0f844b0mblighreading a single source file from standard input and writing the transformed 1909a025e087fa754b633ebc499d5c96d4e0f844b0mblighsource to standard output. In this case, the -d, -r and -v flags are 2009a025e087fa754b633ebc499d5c96d4e0f844b0mblighignored. 2109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 2209a025e087fa754b633ebc499d5c96d4e0f844b0mblighYou can pass one or more file and/or directory paths. When a directory 2309a025e087fa754b633ebc499d5c96d4e0f844b0mblighpath, all .py files within the directory will be examined, and, if the -r 2409a025e087fa754b633ebc499d5c96d4e0f844b0mblighoption is given, likewise recursively for subdirectories. 2509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 2609a025e087fa754b633ebc499d5c96d4e0f844b0mblighIf output is not to standard output, reindent overwrites files in place, 2709a025e087fa754b633ebc499d5c96d4e0f844b0mblighrenaming the originals with a .bak extension. If it finds nothing to 2809a025e087fa754b633ebc499d5c96d4e0f844b0mblighchange, the file is left alone. If reindent does change a file, the changed 2909a025e087fa754b633ebc499d5c96d4e0f844b0mblighfile is a fixed-point for future runs (i.e., running reindent on the 3009a025e087fa754b633ebc499d5c96d4e0f844b0mblighresulting .py file won't change it again). 3109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 3209a025e087fa754b633ebc499d5c96d4e0f844b0mblighThe hard part of reindenting is figuring out what to do with comment 3309a025e087fa754b633ebc499d5c96d4e0f844b0mblighlines. So long as the input files get a clean bill of health from 3409a025e087fa754b633ebc499d5c96d4e0f844b0mblightabnanny.py, reindent should do a good job. 3509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 3609a025e087fa754b633ebc499d5c96d4e0f844b0mblighThe backup file is a copy of the one that is being reindented. The ".bak" 3709a025e087fa754b633ebc499d5c96d4e0f844b0mblighfile is generated with shutil.copy(), but some corner cases regarding 3809a025e087fa754b633ebc499d5c96d4e0f844b0mblighuser/group and permissions could leave the backup file more readable that 3909a025e087fa754b633ebc499d5c96d4e0f844b0mblighyou'd prefer. You can always use the --nobackup option to prevent this. 4009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh""" 4109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 4209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh__version__ = "1" 4309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 4409a025e087fa754b633ebc499d5c96d4e0f844b0mblighimport tokenize 4509a025e087fa754b633ebc499d5c96d4e0f844b0mblighimport os, shutil 4609a025e087fa754b633ebc499d5c96d4e0f844b0mblighimport sys 4709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 4809a025e087fa754b633ebc499d5c96d4e0f844b0mblighverbose = 0 4909a025e087fa754b633ebc499d5c96d4e0f844b0mblighrecurse = 0 5009a025e087fa754b633ebc499d5c96d4e0f844b0mblighdryrun = 0 5109a025e087fa754b633ebc499d5c96d4e0f844b0mblighmakebackup = True 5209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 5309a025e087fa754b633ebc499d5c96d4e0f844b0mblighdef usage(msg=None): 5409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if msg is not None: 5509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print >> sys.stderr, msg 5609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print >> sys.stderr, __doc__ 5709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 5809a025e087fa754b633ebc499d5c96d4e0f844b0mblighdef errprint(*args): 5909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh sep = "" 6009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for arg in args: 6109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh sys.stderr.write(sep + str(arg)) 6209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh sep = " " 6309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh sys.stderr.write("\n") 6409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 6509a025e087fa754b633ebc499d5c96d4e0f844b0mblighdef main(): 6609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh import getopt 6709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh global verbose, recurse, dryrun, makebackup 6809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh try: 6909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh opts, args = getopt.getopt(sys.argv[1:], "drnvh", 7009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh ["dryrun", "recurse", "nobackup", "verbose", "help"]) 7109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh except getopt.error, msg: 7209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh usage(msg) 7309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return 7409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for o, a in opts: 7509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if o in ('-d', '--dryrun'): 7609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh dryrun += 1 7709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif o in ('-r', '--recurse'): 7809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh recurse += 1 7909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif o in ('-n', '--nobackup'): 8009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh makebackup = False 8109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif o in ('-v', '--verbose'): 8209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh verbose += 1 8309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif o in ('-h', '--help'): 8409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh usage() 8509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return 8609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if not args: 8709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh r = Reindenter(sys.stdin) 8809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh r.run() 8909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh r.write(sys.stdout) 9009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return 9109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for arg in args: 9209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh check(arg) 9309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 9409a025e087fa754b633ebc499d5c96d4e0f844b0mblighdef check(file): 9509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if os.path.isdir(file) and not os.path.islink(file): 9609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if verbose: 9709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "listing directory", file 9809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh names = os.listdir(file) 9909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for name in names: 10009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh fullname = os.path.join(file, name) 10109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if ((recurse and os.path.isdir(fullname) and 10209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh not os.path.islink(fullname)) 10309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh or name.lower().endswith(".py")): 10409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh check(fullname) 10509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return 10609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 10709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if verbose: 10809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "checking", file, "...", 10909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh try: 11009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh f = open(file) 11109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh except IOError, msg: 11209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh errprint("%s: I/O Error: %s" % (file, str(msg))) 11309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return 11409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 11509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh r = Reindenter(f) 11609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh f.close() 11709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if r.run(): 11809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if verbose: 11909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "changed." 12009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if dryrun: 12109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "But this is a dry run, so leaving it alone." 12209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if not dryrun: 12309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh bak = file + ".bak" 12409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if makebackup: 12509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh shutil.copyfile(file, bak) 12609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if verbose: 12709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "backed up", file, "to", bak 12809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh f = open(file, "w") 12909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh r.write(f) 13009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh f.close() 13109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if verbose: 13209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "wrote new", file 13309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return True 13409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh else: 13509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if verbose: 13609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh print "unchanged." 13709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return False 13809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 13909a025e087fa754b633ebc499d5c96d4e0f844b0mblighdef _rstrip(line, JUNK='\n \t'): 14009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh """Return line stripped of trailing spaces, tabs, newlines. 14109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 14209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh Note that line.rstrip() instead also strips sundry control characters, 14309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh but at least one known Emacs user expects to keep junk like that, not 14409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh mentioning Barry by name or anything <wink>. 14509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh """ 14609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 14709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh i = len(line) 14809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh while i > 0 and line[i-1] in JUNK: 14909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh i -= 1 15009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return line[:i] 15109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 15209a025e087fa754b633ebc499d5c96d4e0f844b0mblighclass Reindenter: 15309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 15409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh def __init__(self, f): 15509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.find_stmt = 1 # next token begins a fresh stmt? 15609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.level = 0 # current indent level 15709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 15809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Raw file lines. 15909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.raw = f.readlines() 16009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 16109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # File lines, rstripped & tab-expanded. Dummy at start is so 16209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # that we can use tokenize's 1-based line numbering easily. 16309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Note that a line is all-blank iff it's "\n". 16409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.lines = [_rstrip(line).expandtabs() + "\n" 16509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for line in self.raw] 16609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.lines.insert(0, None) 16709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.index = 1 # index into self.lines of next line 16809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 16909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # List of (lineno, indentlevel) pairs, one for each stmt and 17009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # comment line. indentlevel is -1 for comment lines, as a 17109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # signal that tokenize doesn't know what to do about them; 17209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # indeed, they're our headache! 17309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.stats = [] 17409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 17509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh def run(self): 17609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh tokenize.tokenize(self.getline, self.tokeneater) 17709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Remove trailing empty lines. 17809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh lines = self.lines 17909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh while lines and lines[-1] == "\n": 18009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh lines.pop() 18109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Sentinel. 18209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh stats = self.stats 18309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh stats.append((len(lines), 0)) 18409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Map count of leading spaces to # we want. 18509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh have2want = {} 18609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Program after transformation. 18709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh after = self.after = [] 18809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Copy over initial empty lines -- there's nothing to do until 18909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # we see a line with *something* on it. 19009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh i = stats[0][0] 19109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh after.extend(lines[1:i]) 19209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for i in range(len(stats)-1): 19309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh thisstmt, thislevel = stats[i] 19409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh nextstmt = stats[i+1][0] 19509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh have = getlspace(lines[thisstmt]) 19609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh want = thislevel * 4 19709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if want < 0: 19809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # A comment line. 19909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if have: 20009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # An indented comment line. If we saw the same 20109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # indentation before, reuse what it most recently 20209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # mapped to. 20309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh want = have2want.get(have, -1) 20409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if want < 0: 20509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Then it probably belongs to the next real stmt. 20609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for j in xrange(i+1, len(stats)-1): 20709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh jline, jlevel = stats[j] 20809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if jlevel >= 0: 20909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if have == getlspace(lines[jline]): 21009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh want = jlevel * 4 21109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh break 21209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if want < 0: # Maybe it's a hanging 21309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # comment like this one, 21409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # in which case we should shift it like its base 21509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # line got shifted. 21609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for j in xrange(i-1, -1, -1): 21709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh jline, jlevel = stats[j] 21809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if jlevel >= 0: 21909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh want = have + getlspace(after[jline-1]) - \ 22009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh getlspace(lines[jline]) 22109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh break 22209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if want < 0: 22309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Still no luck -- leave it alone. 22409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh want = have 22509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh else: 22609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh want = 0 22709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh assert want >= 0 22809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh have2want[have] = want 22909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh diff = want - have 23009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if diff == 0 or have == 0: 23109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh after.extend(lines[thisstmt:nextstmt]) 23209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh else: 23309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh for line in lines[thisstmt:nextstmt]: 23409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if diff > 0: 23509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if line == "\n": 23609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh after.append(line) 23709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh else: 23809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh after.append(" " * diff + line) 23909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh else: 24009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh remove = min(getlspace(line), -diff) 24109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh after.append(line[remove:]) 24209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return self.raw != self.after 24309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 24409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh def write(self, f): 24509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh f.writelines(self.after) 24609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 24709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Line-getter for tokenize. 24809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh def getline(self): 24909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if self.index >= len(self.lines): 25009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh line = "" 25109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh else: 25209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh line = self.lines[self.index] 25309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.index += 1 25409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return line 25509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 25609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # Line-eater for tokenize. 25709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh def tokeneater(self, type, token, (sline, scol), end, line, 25809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh INDENT=tokenize.INDENT, 25909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh DEDENT=tokenize.DEDENT, 26009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh NEWLINE=tokenize.NEWLINE, 26109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh COMMENT=tokenize.COMMENT, 26209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh NL=tokenize.NL): 26309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 26409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if type == NEWLINE: 26509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # A program statement, or ENDMARKER, will eventually follow, 26609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # after some (possibly empty) run of tokens of the form 26709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # (NL | COMMENT)* (INDENT | DEDENT+)? 26809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.find_stmt = 1 26909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 27009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif type == INDENT: 27109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.find_stmt = 1 27209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.level += 1 27309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 27409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif type == DEDENT: 27509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.find_stmt = 1 27609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.level -= 1 27709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 27809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif type == COMMENT: 27909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if self.find_stmt: 28009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.stats.append((sline, -1)) 28109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # but we're still looking for a new stmt, so leave 28209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # find_stmt alone 28309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 28409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif type == NL: 28509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh pass 28609a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 28709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh elif self.find_stmt: 28809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # This is the first "real token" following a NEWLINE, so it 28909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # must be the first token of the next program statement, or an 29009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh # ENDMARKER. 29109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.find_stmt = 0 29209a025e087fa754b633ebc499d5c96d4e0f844b0mbligh if line: # not endmarker 29309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh self.stats.append((sline, self.level)) 29409a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 29509a025e087fa754b633ebc499d5c96d4e0f844b0mbligh# Count number of leading blanks. 29609a025e087fa754b633ebc499d5c96d4e0f844b0mblighdef getlspace(line): 29709a025e087fa754b633ebc499d5c96d4e0f844b0mbligh i, n = 0, len(line) 29809a025e087fa754b633ebc499d5c96d4e0f844b0mbligh while i < n and line[i] == " ": 29909a025e087fa754b633ebc499d5c96d4e0f844b0mbligh i += 1 30009a025e087fa754b633ebc499d5c96d4e0f844b0mbligh return i 30109a025e087fa754b633ebc499d5c96d4e0f844b0mbligh 30209a025e087fa754b633ebc499d5c96d4e0f844b0mblighif __name__ == '__main__': 30309a025e087fa754b633ebc499d5c96d4e0f844b0mbligh main() 304