| 
									
										
										
										
											2010-03-11 22:53:45 +00:00
										 |  |  | #! /usr/bin/env python3 | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | """fixdiv - tool to fix division operators.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 03:51:09 +00:00
										 |  |  | To use this tool, first run `python -Qwarnall yourscript.py 2>warnings'. | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | This runs the script `yourscript.py' while writing warning messages | 
					
						
							|  |  |  | about all uses of the classic division operator to the file | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | `warnings'.  The warnings look like this: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   <file>:<line>: DeprecationWarning: classic <type> division | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The warnings are written to stderr, so you must use `2>' for the I/O | 
					
						
							|  |  |  | redirect.  I know of no way to redirect stderr on Windows in a DOS | 
					
						
							|  |  |  | box, so you will have to modify the script to set sys.stderr to some | 
					
						
							|  |  |  | kind of log file if you want to do this on Windows. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The warnings are not limited to the script; modules imported by the | 
					
						
							|  |  |  | script may also trigger warnings.  In fact a useful technique is to | 
					
						
							|  |  |  | write a test script specifically intended to exercise all code in a | 
					
						
							|  |  |  | particular module or set of modules. | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Then run `python fixdiv.py warnings'.  This first reads the warnings, | 
					
						
							|  |  |  | looking for classic division warnings, and sorts them by file name and | 
					
						
							|  |  |  | line number.  Then, for each file that received at least one warning, | 
					
						
							|  |  |  | it parses the file and tries to match the warnings up to the division | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | operators found in the source code.  If it is successful, it writes | 
					
						
							|  |  |  | its findings to stdout, preceded by a line of dashes and a line of the | 
					
						
							|  |  |  | form: | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  |   Index: <file> | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | If the only findings found are suggestions to change a / operator into | 
					
						
							|  |  |  | a // operator, the output is acceptable input for the Unix 'patch' | 
					
						
							|  |  |  | program. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Here are the possible messages on stdout (N stands for a line number): | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | - A plain-diff-style change ('NcN', a line marked by '<', a line | 
					
						
							|  |  |  |   containing '---', and a line marked by '>'): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   A / operator was found that should be changed to //.  This is the | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |   recommendation when only int and/or long arguments were seen. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | - 'True division / operator at line N' and a line marked by '=': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   A / operator was found that can remain unchanged.  This is the | 
					
						
							|  |  |  |   recommendation when only float and/or complex arguments were seen. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - 'Ambiguous / operator (..., ...) at line N', line marked by '?': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   A / operator was found for which int or long as well as float or | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |   complex arguments were seen.  This is highly unlikely; if it occurs, | 
					
						
							|  |  |  |   you may have to restructure the code to keep the classic semantics, | 
					
						
							|  |  |  |   or maybe you don't care about the classic semantics. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | - 'No conclusive evidence on line N', line marked by '*': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   A / operator was found for which no warnings were seen.  This could | 
					
						
							| 
									
										
										
										
											2003-10-20 14:01:56 +00:00
										 |  |  |   be code that was never executed, or code that was only executed | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |   with user-defined objects as arguments.  You will have to | 
					
						
							|  |  |  |   investigate further.  Note that // can be overloaded separately from | 
					
						
							|  |  |  |   /, using __floordiv__.  True division can also be separately | 
					
						
							|  |  |  |   overloaded, using __truediv__.  Classic division should be the same | 
					
						
							|  |  |  |   as either of those.  (XXX should I add a warning for division on | 
					
						
							|  |  |  |   user-defined objects, to disambiguate this case from code that was | 
					
						
							|  |  |  |   never executed?) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | - 'Phantom ... warnings for line N', line marked by '*': | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  |   A warning was seen for a line not containing a / operator.  The most | 
					
						
							|  |  |  |   likely cause is a warning about code executed by 'exec' or eval() | 
					
						
							|  |  |  |   (see note below), or an indirect invocation of the / operator, for | 
					
						
							|  |  |  |   example via the div() function in the operator module.  It could | 
					
						
							|  |  |  |   also be caused by a change to the file between the time the test | 
					
						
							|  |  |  |   script was run to collect warnings and the time fixdiv was run. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - 'More than one / operator in line N'; or | 
					
						
							|  |  |  |   'More than one / operator per statement in lines N-N': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   The scanner found more than one / operator on a single line, or in a | 
					
						
							|  |  |  |   statement split across multiple lines.  Because the warnings | 
					
						
							|  |  |  |   framework doesn't (and can't) show the offset within the line, and | 
					
						
							|  |  |  |   the code generator doesn't always give the correct line number for | 
					
						
							|  |  |  |   operations in a multi-line statement, we can't be sure whether all | 
					
						
							|  |  |  |   operators in the statement were executed.  To be on the safe side, | 
					
						
							|  |  |  |   by default a warning is issued about this case.  In practice, these | 
					
						
							|  |  |  |   cases are usually safe, and the -m option suppresses these warning. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - 'Can't find the / operator in line N', line marked by '*': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   This really shouldn't happen.  It means that the tokenize module | 
					
						
							|  |  |  |   reported a '/' operator but the line it returns didn't contain a '/' | 
					
						
							|  |  |  |   character at the indicated position. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - 'Bad warning for line N: XYZ', line marked by '*': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   This really shouldn't happen.  It means that a 'classic XYZ | 
					
						
							|  |  |  |   division' warning was read with XYZ being something other than | 
					
						
							|  |  |  |   'int', 'long', 'float', or 'complex'. | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Notes: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - The augmented assignment operator /= is handled the same way as the | 
					
						
							|  |  |  |   / operator. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - This tool never looks at the // operator; no warnings are ever | 
					
						
							|  |  |  |   generated for use of this operator. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - This tool never looks at the / operator when a future division | 
					
						
							|  |  |  |   statement is in effect; no warnings are generated in this case, and | 
					
						
							|  |  |  |   because the tool only looks at files for which at least one classic | 
					
						
							|  |  |  |   division warning was seen, it will never look at files containing a | 
					
						
							|  |  |  |   future division statement. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Warnings may be issued for code not read from a file, but executed | 
					
						
							| 
									
										
										
										
											2006-09-06 06:51:57 +00:00
										 |  |  |   using the exec() or eval() functions.  These may have | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  |   <string> in the filename position, in which case the fixdiv script | 
					
						
							|  |  |  |   will attempt and fail to open a file named '<string>' and issue a | 
					
						
							|  |  |  |   warning about this failure; or these may be reported as 'Phantom' | 
					
						
							|  |  |  |   warnings (see above).  You're on your own to deal with these.  You | 
					
						
							|  |  |  |   could make all recommended changes and add a future division | 
					
						
							|  |  |  |   statement to all affected files, and then re-run the test script; it | 
					
						
							|  |  |  |   should not issue any warnings.  If there are any, and you have a | 
					
						
							|  |  |  |   hard time tracking down where they are generated, you can use the | 
					
						
							|  |  |  |   -Werror option to force an error instead of a first warning, | 
					
						
							|  |  |  |   generating a traceback. | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | - The tool should be run from the same directory as that from which | 
					
						
							|  |  |  |   the original script was run, otherwise it won't be able to open | 
					
						
							|  |  |  |   files given by relative pathnames. | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import getopt | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import tokenize | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  | multi_ok = 0 | 
					
						
							| 
									
										
										
										
											2001-09-02 14:11:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | def main(): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2001-09-02 14:11:30 +00:00
										 |  |  |         opts, args = getopt.getopt(sys.argv[1:], "hm") | 
					
						
							| 
									
										
										
										
											2007-01-10 16:19:56 +00:00
										 |  |  |     except getopt.error as msg: | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |         usage(msg) | 
					
						
							|  |  |  |         return 2 | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |     for o, a in opts: | 
					
						
							|  |  |  |         if o == "-h": | 
					
						
							| 
									
										
										
										
											2007-08-03 17:06:41 +00:00
										 |  |  |             print(__doc__) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2001-09-02 14:11:30 +00:00
										 |  |  |         if o == "-m": | 
					
						
							|  |  |  |             global multi_ok | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  |             multi_ok = 1 | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |     if not args: | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |         usage("at least one file argument is required") | 
					
						
							|  |  |  |         return 2 | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |     if args[1:]: | 
					
						
							|  |  |  |         sys.stderr.write("%s: extra file arguments ignored\n", sys.argv[0]) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |     warnings = readwarnings(args[0]) | 
					
						
							|  |  |  |     if warnings is None: | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2008-05-16 15:23:30 +00:00
										 |  |  |     files = list(warnings.keys()) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |     if not files: | 
					
						
							| 
									
										
										
										
											2007-08-03 17:06:41 +00:00
										 |  |  |         print("No classic division warnings read from", args[0]) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     files.sort() | 
					
						
							|  |  |  |     exit = None | 
					
						
							| 
									
										
										
										
											2003-05-13 18:14:25 +00:00
										 |  |  |     for filename in files: | 
					
						
							|  |  |  |         x = process(filename, warnings[filename]) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |         exit = exit or x | 
					
						
							|  |  |  |     return exit | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  | def usage(msg): | 
					
						
							|  |  |  |     sys.stderr.write("%s: %s\n" % (sys.argv[0], msg)) | 
					
						
							| 
									
										
										
										
											2001-09-02 14:11:30 +00:00
										 |  |  |     sys.stderr.write("Usage: %s [-m] warnings\n" % sys.argv[0]) | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |     sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-08 13:59:53 -04:00
										 |  |  | PATTERN = (r"^(.+?):(\d+): DeprecationWarning: " | 
					
						
							|  |  |  |            r"classic (int|long|float|complex) division$") | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def readwarnings(warningsfile): | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |     prog = re.compile(PATTERN) | 
					
						
							| 
									
										
										
										
											2019-03-30 08:32:18 +02:00
										 |  |  |     warnings = {} | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         f = open(warningsfile) | 
					
						
							| 
									
										
										
										
											2007-01-10 16:19:56 +00:00
										 |  |  |     except IOError as msg: | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |         sys.stderr.write("can't open: %s\n" % msg) | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-03-30 08:32:18 +02:00
										 |  |  |     with f: | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             line = f.readline() | 
					
						
							|  |  |  |             if not line: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             m = prog.match(line) | 
					
						
							|  |  |  |             if not m: | 
					
						
							|  |  |  |                 if line.find("division") >= 0: | 
					
						
							|  |  |  |                     sys.stderr.write("Warning: ignored input " + line) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             filename, lineno, what = m.groups() | 
					
						
							|  |  |  |             list = warnings.get(filename) | 
					
						
							|  |  |  |             if list is None: | 
					
						
							|  |  |  |                 warnings[filename] = list = [] | 
					
						
							|  |  |  |             list.append((int(lineno), sys.intern(what))) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |     return warnings | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-13 18:14:25 +00:00
										 |  |  | def process(filename, list): | 
					
						
							| 
									
										
										
										
											2007-08-03 17:06:41 +00:00
										 |  |  |     print("-"*70) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |     assert list # if this fails, readwarnings() is broken | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2003-05-13 18:14:25 +00:00
										 |  |  |         fp = open(filename) | 
					
						
							| 
									
										
										
										
											2007-01-10 16:19:56 +00:00
										 |  |  |     except IOError as msg: | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |         sys.stderr.write("can't open: %s\n" % msg) | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-03-30 08:32:18 +02:00
										 |  |  |     with fp: | 
					
						
							|  |  |  |         print("Index:", filename) | 
					
						
							|  |  |  |         f = FileContext(fp) | 
					
						
							|  |  |  |         list.sort() | 
					
						
							|  |  |  |         index = 0 # list[:index] has been processed, list[index:] is still to do | 
					
						
							|  |  |  |         g = tokenize.generate_tokens(f.readline) | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             startlineno, endlineno, slashes = lineinfo = scanline(g) | 
					
						
							|  |  |  |             if startlineno is None: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             assert startlineno <= endlineno is not None | 
					
						
							|  |  |  |             orphans = [] | 
					
						
							|  |  |  |             while index < len(list) and list[index][0] < startlineno: | 
					
						
							|  |  |  |                 orphans.append(list[index]) | 
					
						
							|  |  |  |                 index += 1 | 
					
						
							|  |  |  |             if orphans: | 
					
						
							|  |  |  |                 reportphantomwarnings(orphans, f) | 
					
						
							|  |  |  |             warnings = [] | 
					
						
							|  |  |  |             while index < len(list) and list[index][0] <= endlineno: | 
					
						
							|  |  |  |                 warnings.append(list[index]) | 
					
						
							|  |  |  |                 index += 1 | 
					
						
							|  |  |  |             if not slashes and not warnings: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             elif slashes and not warnings: | 
					
						
							|  |  |  |                 report(slashes, "No conclusive evidence") | 
					
						
							|  |  |  |             elif warnings and not slashes: | 
					
						
							|  |  |  |                 reportphantomwarnings(warnings, f) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if len(slashes) > 1: | 
					
						
							|  |  |  |                     if not multi_ok: | 
					
						
							|  |  |  |                         rows = [] | 
					
						
							|  |  |  |                         lastrow = None | 
					
						
							|  |  |  |                         for (row, col), line in slashes: | 
					
						
							|  |  |  |                             if row == lastrow: | 
					
						
							|  |  |  |                                 continue | 
					
						
							|  |  |  |                             rows.append(row) | 
					
						
							|  |  |  |                             lastrow = row | 
					
						
							|  |  |  |                         assert rows | 
					
						
							|  |  |  |                         if len(rows) == 1: | 
					
						
							|  |  |  |                             print("*** More than one / operator in line", rows[0]) | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             print("*** More than one / operator per statement", end=' ') | 
					
						
							|  |  |  |                             print("in lines %d-%d" % (rows[0], rows[-1])) | 
					
						
							|  |  |  |                 intlong = [] | 
					
						
							|  |  |  |                 floatcomplex = [] | 
					
						
							|  |  |  |                 bad = [] | 
					
						
							|  |  |  |                 for lineno, what in warnings: | 
					
						
							|  |  |  |                     if what in ("int", "long"): | 
					
						
							|  |  |  |                         intlong.append(what) | 
					
						
							|  |  |  |                     elif what in ("float", "complex"): | 
					
						
							|  |  |  |                         floatcomplex.append(what) | 
					
						
							| 
									
										
										
										
											2001-09-04 16:22:01 +00:00
										 |  |  |                     else: | 
					
						
							| 
									
										
										
										
											2019-03-30 08:32:18 +02:00
										 |  |  |                         bad.append(what) | 
					
						
							|  |  |  |                 lastrow = None | 
					
						
							|  |  |  |                 for (row, col), line in slashes: | 
					
						
							|  |  |  |                     if row == lastrow: | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     lastrow = row | 
					
						
							|  |  |  |                     line = chop(line) | 
					
						
							|  |  |  |                     if line[col:col+1] != "/": | 
					
						
							|  |  |  |                         print("*** Can't find the / operator in line %d:" % row) | 
					
						
							|  |  |  |                         print("*", line) | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     if bad: | 
					
						
							|  |  |  |                         print("*** Bad warning for line %d:" % row, bad) | 
					
						
							|  |  |  |                         print("*", line) | 
					
						
							|  |  |  |                     elif intlong and not floatcomplex: | 
					
						
							|  |  |  |                         print("%dc%d" % (row, row)) | 
					
						
							|  |  |  |                         print("<", line) | 
					
						
							|  |  |  |                         print("---") | 
					
						
							|  |  |  |                         print(">", line[:col] + "/" + line[col:]) | 
					
						
							|  |  |  |                     elif floatcomplex and not intlong: | 
					
						
							|  |  |  |                         print("True division / operator at line %d:" % row) | 
					
						
							|  |  |  |                         print("=", line) | 
					
						
							|  |  |  |                     elif intlong and floatcomplex: | 
					
						
							|  |  |  |                         print("*** Ambiguous / operator (%s, %s) at line %d:" % | 
					
						
							|  |  |  |                             ("|".join(intlong), "|".join(floatcomplex), row)) | 
					
						
							|  |  |  |                         print("?", line) | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def reportphantomwarnings(warnings, f): | 
					
						
							|  |  |  |     blocks = [] | 
					
						
							|  |  |  |     lastrow = None | 
					
						
							|  |  |  |     lastblock = None | 
					
						
							|  |  |  |     for row, what in warnings: | 
					
						
							|  |  |  |         if row != lastrow: | 
					
						
							|  |  |  |             lastblock = [row] | 
					
						
							|  |  |  |             blocks.append(lastblock) | 
					
						
							|  |  |  |         lastblock.append(what) | 
					
						
							|  |  |  |     for block in blocks: | 
					
						
							|  |  |  |         row = block[0] | 
					
						
							|  |  |  |         whats = "/".join(block[1:]) | 
					
						
							| 
									
										
										
										
											2007-08-03 17:06:41 +00:00
										 |  |  |         print("*** Phantom %s warnings for line %d:" % (whats, row)) | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |         f.report(row, mark="*") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def report(slashes, message): | 
					
						
							|  |  |  |     lastrow = None | 
					
						
							|  |  |  |     for (row, col), line in slashes: | 
					
						
							|  |  |  |         if row != lastrow: | 
					
						
							| 
									
										
										
										
											2007-08-03 17:06:41 +00:00
										 |  |  |             print("*** %s on line %d:" % (message, row)) | 
					
						
							|  |  |  |             print("*", chop(line)) | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  |             lastrow = row | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FileContext: | 
					
						
							|  |  |  |     def __init__(self, fp, window=5, lineno=1): | 
					
						
							|  |  |  |         self.fp = fp | 
					
						
							|  |  |  |         self.window = 5 | 
					
						
							|  |  |  |         self.lineno = 1 | 
					
						
							|  |  |  |         self.eoflookahead = 0 | 
					
						
							|  |  |  |         self.lookahead = [] | 
					
						
							|  |  |  |         self.buffer = [] | 
					
						
							|  |  |  |     def fill(self): | 
					
						
							|  |  |  |         while len(self.lookahead) < self.window and not self.eoflookahead: | 
					
						
							|  |  |  |             line = self.fp.readline() | 
					
						
							|  |  |  |             if not line: | 
					
						
							|  |  |  |                 self.eoflookahead = 1 | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             self.lookahead.append(line) | 
					
						
							|  |  |  |     def readline(self): | 
					
						
							|  |  |  |         self.fill() | 
					
						
							|  |  |  |         if not self.lookahead: | 
					
						
							|  |  |  |             return "" | 
					
						
							|  |  |  |         line = self.lookahead.pop(0) | 
					
						
							|  |  |  |         self.buffer.append(line) | 
					
						
							|  |  |  |         self.lineno += 1 | 
					
						
							|  |  |  |         return line | 
					
						
							|  |  |  |     def __getitem__(self, index): | 
					
						
							|  |  |  |         self.fill() | 
					
						
							|  |  |  |         bufstart = self.lineno - len(self.buffer) | 
					
						
							|  |  |  |         lookend = self.lineno + len(self.lookahead) | 
					
						
							|  |  |  |         if bufstart <= index < self.lineno: | 
					
						
							|  |  |  |             return self.buffer[index - bufstart] | 
					
						
							|  |  |  |         if self.lineno <= index < lookend: | 
					
						
							|  |  |  |             return self.lookahead[index - self.lineno] | 
					
						
							|  |  |  |         raise KeyError | 
					
						
							|  |  |  |     def report(self, first, last=None, mark="*"): | 
					
						
							|  |  |  |         if last is None: | 
					
						
							|  |  |  |             last = first | 
					
						
							|  |  |  |         for i in range(first, last+1): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 line = self[first] | 
					
						
							|  |  |  |             except KeyError: | 
					
						
							|  |  |  |                 line = "<missing line>" | 
					
						
							| 
									
										
										
										
											2007-08-03 17:06:41 +00:00
										 |  |  |             print(mark, chop(line)) | 
					
						
							| 
									
										
										
										
											2001-09-01 21:55:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def scanline(g): | 
					
						
							|  |  |  |     slashes = [] | 
					
						
							|  |  |  |     startlineno = None | 
					
						
							|  |  |  |     endlineno = None | 
					
						
							|  |  |  |     for type, token, start, end, line in g: | 
					
						
							|  |  |  |         endlineno = end[0] | 
					
						
							|  |  |  |         if startlineno is None: | 
					
						
							|  |  |  |             startlineno = endlineno | 
					
						
							|  |  |  |         if token in ("/", "/="): | 
					
						
							|  |  |  |             slashes.append((start, line)) | 
					
						
							|  |  |  |         if type == tokenize.NEWLINE: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |     return startlineno, endlineno, slashes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def chop(line): | 
					
						
							|  |  |  |     if line.endswith("\n"): | 
					
						
							|  |  |  |         return line[:-1] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return line | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2001-09-02 04:49:36 +00:00
										 |  |  |     sys.exit(main()) |