12 from . import refactor
15 def diff_texts(a
, b
, filename
):
16 """Return a unified diff of two strings."""
19 return difflib
.unified_diff(a
, b
, filename
, filename
,
20 "(original)", "(refactored)",
24 class StdoutRefactoringTool(refactor
.MultiprocessRefactoringTool
):
26 Prints output to stdout.
29 def __init__(self
, fixers
, options
, explicit
, nobackups
, show_diffs
):
30 self
.nobackups
= nobackups
31 self
.show_diffs
= show_diffs
32 super(StdoutRefactoringTool
, self
).__init
__(fixers
, options
, explicit
)
34 def log_error(self
, msg
, *args
, **kwargs
):
35 self
.errors
.append((msg
, args
, kwargs
))
36 self
.logger
.error(msg
, *args
, **kwargs
)
38 def write_file(self
, new_text
, filename
, old_text
, encoding
):
39 if not self
.nobackups
:
41 backup
= filename
+ ".bak"
42 if os
.path
.lexists(backup
):
46 self
.log_message("Can't remove backup %s", backup
)
48 os
.rename(filename
, backup
)
50 self
.log_message("Can't rename %s to %s", filename
, backup
)
51 # Actually write the new file
52 write
= super(StdoutRefactoringTool
, self
).write_file
53 write(new_text
, filename
, old_text
, encoding
)
54 if not self
.nobackups
:
55 shutil
.copymode(backup
, filename
)
57 def print_output(self
, old
, new
, filename
, equal
):
59 self
.log_message("No changes to %s", filename
)
61 self
.log_message("Refactored %s", filename
)
63 for line
in diff_texts(old
, new
, filename
):
68 print >> sys
.stderr
, "WARNING: %s" % (msg
,)
71 def main(fixer_pkg
, args
=None):
75 fixer_pkg: the name of a package where the fixers are located.
76 args: optional; a list of command line arguments. If omitted,
79 Returns a suggested exit status (0, 1, 2).
81 # Set up option parser
82 parser
= optparse
.OptionParser(usage
="2to3 [options] file|dir ...")
83 parser
.add_option("-d", "--doctests_only", action
="store_true",
84 help="Fix up doctests only")
85 parser
.add_option("-f", "--fix", action
="append", default
=[],
86 help="Each FIX specifies a transformation; default: all")
87 parser
.add_option("-j", "--processes", action
="store", default
=1,
88 type="int", help="Run 2to3 concurrently")
89 parser
.add_option("-x", "--nofix", action
="append", default
=[],
90 help="Prevent a fixer from being run.")
91 parser
.add_option("-l", "--list-fixes", action
="store_true",
92 help="List available transformations (fixes/fix_*.py)")
93 parser
.add_option("-p", "--print-function", action
="store_true",
94 help="Modify the grammar so that print() is a function")
95 parser
.add_option("-v", "--verbose", action
="store_true",
96 help="More verbose logging")
97 parser
.add_option("--no-diffs", action
="store_true",
98 help="Don't show diffs of the refactoring")
99 parser
.add_option("-w", "--write", action
="store_true",
100 help="Write back modified files")
101 parser
.add_option("-n", "--nobackups", action
="store_true", default
=False,
102 help="Don't write backups for modified files.")
104 # Parse command line arguments
105 refactor_stdin
= False
107 options
, args
= parser
.parse_args(args
)
108 if not options
.write
and options
.no_diffs
:
109 warn("not writing files and not printing diffs; that's not very useful")
110 if not options
.write
and options
.nobackups
:
111 parser
.error("Can't use -n without -w")
112 if options
.list_fixes
:
113 print "Available transformations for the -f/--fix option:"
114 for fixname
in refactor
.get_all_fix_names(fixer_pkg
):
119 print >> sys
.stderr
, "At least one file or directory argument required."
120 print >> sys
.stderr
, "Use --help to show usage."
123 refactor_stdin
= True
125 print >> sys
.stderr
, "Can't write to stdin."
127 if options
.print_function
:
128 flags
["print_function"] = True
130 # Set up logging handler
131 level
= logging
.DEBUG
if options
.verbose
else logging
.INFO
132 logging
.basicConfig(format
='%(name)s: %(message)s', level
=level
)
134 # Initialize the refactoring tool
135 avail_fixes
= set(refactor
.get_fixers_from_package(fixer_pkg
))
136 unwanted_fixes
= set(fixer_pkg
+ ".fix_" + fix
for fix
in options
.nofix
)
140 for fix
in options
.fix
:
144 explicit
.add(fixer_pkg
+ ".fix_" + fix
)
145 requested
= avail_fixes
.union(explicit
) if all_present
else explicit
147 requested
= avail_fixes
.union(explicit
)
148 fixer_names
= requested
.difference(unwanted_fixes
)
149 rt
= StdoutRefactoringTool(sorted(fixer_names
), flags
, sorted(explicit
),
150 options
.nobackups
, not options
.no_diffs
)
152 # Refactor all files and directories passed as arguments
158 rt
.refactor(args
, options
.write
, options
.doctests_only
,
160 except refactor
.MultiprocessingUnsupported
:
161 assert options
.processes
> 1
162 print >> sys
.stderr
, "Sorry, -j isn't " \
163 "supported on this platform."
167 # Return error status (0 if rt.errors is zero)
168 return int(bool(rt
.errors
))