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
):
45 except os
.error
as err
:
46 self
.log_message("Can't remove backup %s", backup
)
48 os
.rename(filename
, backup
)
49 except os
.error
as err
:
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 diff_lines
= diff_texts(old
, new
, filename
)
65 for line
in diff_lines
:
67 except UnicodeEncodeError:
68 warn("couldn't encode %s's diff for your terminal" %
73 print("WARNING: %s" % (msg
,), file=sys
.stderr
)
76 def main(fixer_pkg
, args
=None):
80 fixer_pkg: the name of a package where the fixers are located.
81 args: optional; a list of command line arguments. If omitted,
84 Returns a suggested exit status (0, 1, 2).
86 # Set up option parser
87 parser
= optparse
.OptionParser(usage
="2to3 [options] file|dir ...")
88 parser
.add_option("-d", "--doctests_only", action
="store_true",
89 help="Fix up doctests only")
90 parser
.add_option("-f", "--fix", action
="append", default
=[],
91 help="Each FIX specifies a transformation; default: all")
92 parser
.add_option("-j", "--processes", action
="store", default
=1,
93 type="int", help="Run 2to3 concurrently")
94 parser
.add_option("-x", "--nofix", action
="append", default
=[],
95 help="Prevent a fixer from being run.")
96 parser
.add_option("-l", "--list-fixes", action
="store_true",
97 help="List available transformations (fixes/fix_*.py)")
98 parser
.add_option("-p", "--print-function", action
="store_true",
99 help="Modify the grammar so that print() is a function")
100 parser
.add_option("-v", "--verbose", action
="store_true",
101 help="More verbose logging")
102 parser
.add_option("--no-diffs", action
="store_true",
103 help="Don't show diffs of the refactoring")
104 parser
.add_option("-w", "--write", action
="store_true",
105 help="Write back modified files")
106 parser
.add_option("-n", "--nobackups", action
="store_true", default
=False,
107 help="Don't write backups for modified files.")
109 # Parse command line arguments
110 refactor_stdin
= False
112 options
, args
= parser
.parse_args(args
)
113 if not options
.write
and options
.no_diffs
:
114 warn("not writing files and not printing diffs; that's not very useful")
115 if not options
.write
and options
.nobackups
:
116 parser
.error("Can't use -n without -w")
117 if options
.list_fixes
:
118 print("Available transformations for the -f/--fix option:")
119 for fixname
in refactor
.get_all_fix_names(fixer_pkg
):
124 print("At least one file or directory argument required.", file=sys
.stderr
)
125 print("Use --help to show usage.", file=sys
.stderr
)
128 refactor_stdin
= True
130 print("Can't write to stdin.", file=sys
.stderr
)
132 if options
.print_function
:
133 flags
["print_function"] = True
135 # Set up logging handler
136 level
= logging
.DEBUG
if options
.verbose
else logging
.INFO
137 logging
.basicConfig(format
='%(name)s: %(message)s', level
=level
)
139 # Initialize the refactoring tool
140 avail_fixes
= set(refactor
.get_fixers_from_package(fixer_pkg
))
141 unwanted_fixes
= set(fixer_pkg
+ ".fix_" + fix
for fix
in options
.nofix
)
145 for fix
in options
.fix
:
149 explicit
.add(fixer_pkg
+ ".fix_" + fix
)
150 requested
= avail_fixes
.union(explicit
) if all_present
else explicit
152 requested
= avail_fixes
.union(explicit
)
153 fixer_names
= requested
.difference(unwanted_fixes
)
154 rt
= StdoutRefactoringTool(sorted(fixer_names
), flags
, sorted(explicit
),
155 options
.nobackups
, not options
.no_diffs
)
157 # Refactor all files and directories passed as arguments
163 rt
.refactor(args
, options
.write
, options
.doctests_only
,
165 except refactor
.MultiprocessingUnsupported
:
166 assert options
.processes
> 1
167 print("Sorry, -j isn't supported on this platform.",
172 # Return error status (0 if rt.errors is zero)
173 return int(bool(rt
.errors
))