diff -r ffa851df0825 -r 2fb8b9db1c86 symbian-qemu-0.9.1-12/python-win32-2.6.1/Tools/Scripts/cleanfuture.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/symbian-qemu-0.9.1-12/python-win32-2.6.1/Tools/Scripts/cleanfuture.py Fri Jul 31 15:01:17 2009 +0100 @@ -0,0 +1,276 @@ +#! /usr/bin/env python + +"""cleanfuture [-d][-r][-v] path ... + +-d Dry run. Analyze, but don't make any changes to, files. +-r Recurse. Search for all .py files in subdirectories too. +-v Verbose. Print informative msgs. + +Search Python (.py) files for future statements, and remove the features +from such statements that are already mandatory in the version of Python +you're using. + +Pass one or more file and/or directory paths. When a directory path, all +.py files within the directory will be examined, and, if the -r option is +given, likewise recursively for subdirectories. + +Overwrites files in place, renaming the originals with a .bak extension. If +cleanfuture finds nothing to change, the file is left alone. If cleanfuture +does change a file, the changed file is a fixed-point (i.e., running +cleanfuture on the resulting .py file won't change it again, at least not +until you try it again with a later Python release). + +Limitations: You can do these things, but this tool won't help you then: + ++ A future statement cannot be mixed with any other statement on the same + physical line (separated by semicolon). + ++ A future statement cannot contain an "as" clause. + +Example: Assuming you're using Python 2.2, if a file containing + +from __future__ import nested_scopes, generators + +is analyzed by cleanfuture, the line is rewritten to + +from __future__ import generators + +because nested_scopes is no longer optional in 2.2 but generators is. +""" + +import __future__ +import tokenize +import os +import sys + +dryrun = 0 +recurse = 0 +verbose = 0 + +def errprint(*args): + strings = map(str, args) + msg = ' '.join(strings) + if msg[-1:] != '\n': + msg += '\n' + sys.stderr.write(msg) + +def main(): + import getopt + global verbose, recurse, dryrun + try: + opts, args = getopt.getopt(sys.argv[1:], "drv") + except getopt.error, msg: + errprint(msg) + return + for o, a in opts: + if o == '-d': + dryrun += 1 + elif o == '-r': + recurse += 1 + elif o == '-v': + verbose += 1 + if not args: + errprint("Usage:", __doc__) + return + for arg in args: + check(arg) + +def check(file): + if os.path.isdir(file) and not os.path.islink(file): + if verbose: + print "listing directory", file + names = os.listdir(file) + for name in names: + fullname = os.path.join(file, name) + if ((recurse and os.path.isdir(fullname) and + not os.path.islink(fullname)) + or name.lower().endswith(".py")): + check(fullname) + return + + if verbose: + print "checking", file, "...", + try: + f = open(file) + except IOError, msg: + errprint("%r: I/O Error: %s" % (file, str(msg))) + return + + ff = FutureFinder(f, file) + changed = ff.run() + if changed: + ff.gettherest() + f.close() + if changed: + if verbose: + print "changed." + if dryrun: + print "But this is a dry run, so leaving it alone." + for s, e, line in changed: + print "%r lines %d-%d" % (file, s+1, e+1) + for i in range(s, e+1): + print ff.lines[i], + if line is None: + print "-- deleted" + else: + print "-- change to:" + print line, + if not dryrun: + bak = file + ".bak" + if os.path.exists(bak): + os.remove(bak) + os.rename(file, bak) + if verbose: + print "renamed", file, "to", bak + g = open(file, "w") + ff.write(g) + g.close() + if verbose: + print "wrote new", file + else: + if verbose: + print "unchanged." + +class FutureFinder: + + def __init__(self, f, fname): + self.f = f + self.fname = fname + self.ateof = 0 + self.lines = [] # raw file lines + + # List of (start_index, end_index, new_line) triples. + self.changed = [] + + # Line-getter for tokenize. + def getline(self): + if self.ateof: + return "" + line = self.f.readline() + if line == "": + self.ateof = 1 + else: + self.lines.append(line) + return line + + def run(self): + STRING = tokenize.STRING + NL = tokenize.NL + NEWLINE = tokenize.NEWLINE + COMMENT = tokenize.COMMENT + NAME = tokenize.NAME + OP = tokenize.OP + + changed = self.changed + get = tokenize.generate_tokens(self.getline).next + type, token, (srow, scol), (erow, ecol), line = get() + + # Chew up initial comments and blank lines (if any). + while type in (COMMENT, NL, NEWLINE): + type, token, (srow, scol), (erow, ecol), line = get() + + # Chew up docstring (if any -- and it may be implicitly catenated!). + while type is STRING: + type, token, (srow, scol), (erow, ecol), line = get() + + # Analyze the future stmts. + while 1: + # Chew up comments and blank lines (if any). + while type in (COMMENT, NL, NEWLINE): + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is NAME and token == "from"): + break + startline = srow - 1 # tokenize is one-based + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is NAME and token == "__future__"): + break + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is NAME and token == "import"): + break + type, token, (srow, scol), (erow, ecol), line = get() + + # Get the list of features. + features = [] + while type is NAME: + features.append(token) + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is OP and token == ','): + break + type, token, (srow, scol), (erow, ecol), line = get() + + # A trailing comment? + comment = None + if type is COMMENT: + comment = token + type, token, (srow, scol), (erow, ecol), line = get() + + if type is not NEWLINE: + errprint("Skipping file %r; can't parse line %d:\n%s" % + (self.fname, srow, line)) + return [] + + endline = srow - 1 + + # Check for obsolete features. + okfeatures = [] + for f in features: + object = getattr(__future__, f, None) + if object is None: + # A feature we don't know about yet -- leave it in. + # They'll get a compile-time error when they compile + # this program, but that's not our job to sort out. + okfeatures.append(f) + else: + released = object.getMandatoryRelease() + if released is None or released <= sys.version_info: + # Withdrawn or obsolete. + pass + else: + okfeatures.append(f) + + # Rewrite the line if at least one future-feature is obsolete. + if len(okfeatures) < len(features): + if len(okfeatures) == 0: + line = None + else: + line = "from __future__ import " + line += ', '.join(okfeatures) + if comment is not None: + line += ' ' + comment + line += '\n' + changed.append((startline, endline, line)) + + # Loop back for more future statements. + + return changed + + def gettherest(self): + if self.ateof: + self.therest = '' + else: + self.therest = self.f.read() + + def write(self, f): + changed = self.changed + assert changed + # Prevent calling this again. + self.changed = [] + # Apply changes in reverse order. + changed.reverse() + for s, e, line in changed: + if line is None: + # pure deletion + del self.lines[s:e+1] + else: + self.lines[s:e+1] = [line] + f.writelines(self.lines) + # Copy over the remainder of the file. + if self.therest: + f.write(self.therest) + +if __name__ == '__main__': + main()