5 from __future__
import with_statement
14 from . import refactor
17 def diff_texts(a
, b
, filename
):
18 """Return a unified diff of two strings."""
21 return difflib
.unified_diff(a
, b
, filename
, filename
,
22 "(original)", "(refactored)",
26 class StdoutRefactoringTool(refactor
.MultiprocessRefactoringTool
):
28 Prints output to stdout.
31 def __init__(self
, fixers
, options
, explicit
, nobackups
, show_diffs
):
32 self
.nobackups
= nobackups
33 self
.show_diffs
= show_diffs
34 super(StdoutRefactoringTool
, self
).__init
__(fixers
, options
, explicit
)
36 def log_error(self
, msg
, *args
, **kwargs
):
37 self
.errors
.append((msg
, args
, kwargs
))
38 self
.logger
.error(msg
, *args
, **kwargs
)
40 def write_file(self
, new_text
, filename
, old_text
, encoding
):
41 if not self
.nobackups
:
43 backup
= filename
+ ".bak"
44 if os
.path
.lexists(backup
):
48 self
.log_message("Can't remove backup %s", backup
)
50 os
.rename(filename
, backup
)
52 self
.log_message("Can't rename %s to %s", filename
, backup
)
53 # Actually write the new file
54 write
= super(StdoutRefactoringTool
, self
).write_file
55 write(new_text
, filename
, old_text
, encoding
)
56 if not self
.nobackups
:
57 shutil
.copymode(backup
, filename
)
59 def print_output(self
, old
, new
, filename
, equal
):
61 self
.log_message("No changes to %s", filename
)
63 self
.log_message("Refactored %s", filename
)
65 diff_lines
= diff_texts(old
, new
, filename
)
67 if self
.output_lock
is not None:
68 with self
.output_lock
:
69 for line
in diff_lines
:
73 for line
in diff_lines
:
75 except UnicodeEncodeError:
76 warn("couldn't encode %s's diff for your terminal" %
82 print >> sys
.stderr
, "WARNING: %s" % (msg
,)
85 def main(fixer_pkg
, args
=None):
89 fixer_pkg: the name of a package where the fixers are located.
90 args: optional; a list of command line arguments. If omitted,
93 Returns a suggested exit status (0, 1, 2).
95 # Set up option parser
96 parser
= optparse
.OptionParser(usage
="2to3 [options] file|dir ...")
97 parser
.add_option("-d", "--doctests_only", action
="store_true",
98 help="Fix up doctests only")
99 parser
.add_option("-f", "--fix", action
="append", default
=[],
100 help="Each FIX specifies a transformation; default: all")
101 parser
.add_option("-j", "--processes", action
="store", default
=1,
102 type="int", help="Run 2to3 concurrently")
103 parser
.add_option("-x", "--nofix", action
="append", default
=[],
104 help="Prevent a transformation from being run")
105 parser
.add_option("-l", "--list-fixes", action
="store_true",
106 help="List available transformations")
107 parser
.add_option("-p", "--print-function", action
="store_true",
108 help="Modify the grammar so that print() is a function")
109 parser
.add_option("-v", "--verbose", action
="store_true",
110 help="More verbose logging")
111 parser
.add_option("--no-diffs", action
="store_true",
112 help="Don't show diffs of the refactoring")
113 parser
.add_option("-w", "--write", action
="store_true",
114 help="Write back modified files")
115 parser
.add_option("-n", "--nobackups", action
="store_true", default
=False,
116 help="Don't write backups for modified files")
118 # Parse command line arguments
119 refactor_stdin
= False
121 options
, args
= parser
.parse_args(args
)
122 if not options
.write
and options
.no_diffs
:
123 warn("not writing files and not printing diffs; that's not very useful")
124 if not options
.write
and options
.nobackups
:
125 parser
.error("Can't use -n without -w")
126 if options
.list_fixes
:
127 print "Available transformations for the -f/--fix option:"
128 for fixname
in refactor
.get_all_fix_names(fixer_pkg
):
133 print >> sys
.stderr
, "At least one file or directory argument required."
134 print >> sys
.stderr
, "Use --help to show usage."
137 refactor_stdin
= True
139 print >> sys
.stderr
, "Can't write to stdin."
141 if options
.print_function
:
142 flags
["print_function"] = True
144 # Set up logging handler
145 level
= logging
.DEBUG
if options
.verbose
else logging
.INFO
146 logging
.basicConfig(format
='%(name)s: %(message)s', level
=level
)
148 # Initialize the refactoring tool
149 avail_fixes
= set(refactor
.get_fixers_from_package(fixer_pkg
))
150 unwanted_fixes
= set(fixer_pkg
+ ".fix_" + fix
for fix
in options
.nofix
)
154 for fix
in options
.fix
:
158 explicit
.add(fixer_pkg
+ ".fix_" + fix
)
159 requested
= avail_fixes
.union(explicit
) if all_present
else explicit
161 requested
= avail_fixes
.union(explicit
)
162 fixer_names
= requested
.difference(unwanted_fixes
)
163 rt
= StdoutRefactoringTool(sorted(fixer_names
), flags
, sorted(explicit
),
164 options
.nobackups
, not options
.no_diffs
)
166 # Refactor all files and directories passed as arguments
172 rt
.refactor(args
, options
.write
, options
.doctests_only
,
174 except refactor
.MultiprocessingUnsupported
:
175 assert options
.processes
> 1
176 print >> sys
.stderr
, "Sorry, -j isn't " \
177 "supported on this platform."
181 # Return error status (0 if rt.errors is zero)
182 return int(bool(rt
.errors
))