Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: third_party/google-endpoints/libfuturize/main.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 """
2 futurize: automatic conversion to clean 2/3 code using ``python-future``
3 ======================================================================
4
5 Like Armin Ronacher's modernize.py, ``futurize`` attempts to produce clean
6 standard Python 3 code that runs on both Py2 and Py3.
7
8 One pass
9 --------
10
11 Use it like this on Python 2 code:
12
13 $ futurize --verbose mypython2script.py
14
15 This will attempt to port the code to standard Py3 code that also
16 provides Py2 compatibility with the help of the right imports from
17 ``future``.
18
19 To write changes to the files, use the -w flag.
20
21 Two stages
22 ----------
23
24 The ``futurize`` script can also be called in two separate stages. First:
25
26 $ futurize --stage1 mypython2script.py
27
28 This produces more modern Python 2 code that is not yet compatible with Python
29 3. The tests should still run and the diff should be uncontroversial to apply to
30 most Python projects that are willing to drop support for Python 2.5 and lower.
31
32 After this, the recommended approach is to explicitly mark all strings that must
33 be byte-strings with a b'' prefix and all text (unicode) strings with a u''
34 prefix, and then invoke the second stage of Python 2 to 2/3 conversion with::
35
36 $ futurize --stage2 mypython2script.py
37
38 Stage 2 adds a dependency on ``future``. It converts most remaining Python
39 2-specific code to Python 3 code and adds appropriate imports from ``future``
40 to restore Py2 support.
41
42 The command above leaves all unadorned string literals as native strings
43 (byte-strings on Py2, unicode strings on Py3). If instead you would like all
44 unadorned string literals to be promoted to unicode, you can also pass this
45 flag:
46
47 $ futurize --stage2 --unicode-literals mypython2script.py
48
49 This adds the declaration ``from __future__ import unicode_literals`` to the
50 top of each file, which implicitly declares all unadorned string literals to be
51 unicode strings (``unicode`` on Py2).
52
53 All imports
54 -----------
55
56 The --all-imports option forces adding all ``__future__`` imports,
57 ``builtins`` imports, and standard library aliases, even if they don't
58 seem necessary for the current state of each module. (This can simplify
59 testing, and can reduce the need to think about Py2 compatibility when editing
60 the code further.)
61
62 """
63
64 from __future__ import (absolute_import, print_function, unicode_literals)
65 import future.utils
66 from future import __version__
67
68 import sys
69 import logging
70 import optparse
71 import os
72
73 from lib2to3.main import main, warn, StdoutRefactoringTool
74 from lib2to3 import refactor
75
76 from libfuturize.fixes import (lib2to3_fix_names_stage1,
77 lib2to3_fix_names_stage2,
78 libfuturize_fix_names_stage1,
79 libfuturize_fix_names_stage2)
80
81 fixer_pkg = 'libfuturize.fixes'
82
83
84 def main(args=None):
85 """Main program.
86
87 Args:
88 fixer_pkg: the name of a package where the fixers are located.
89 args: optional; a list of command line arguments. If omitted,
90 sys.argv[1:] is used.
91
92 Returns a suggested exit status (0, 1, 2).
93 """
94
95 # Set up option parser
96 parser = optparse.OptionParser(usage="futurize [options] file|dir ...")
97 parser.add_option("-V", "--version", action="store_true",
98 help="Report the version number of futurize")
99 parser.add_option("-a", "--all-imports", action="store_true",
100 help="Add all __future__ and future imports to each module ")
101 parser.add_option("-1", "--stage1", action="store_true",
102 help="Modernize Python 2 code only; no compatibility with Python 3 (or dependency on ``future``)")
103 parser.add_option("-2", "--stage2", action="store_true",
104 help="Take modernized (stage1) code and add a dependency o n ``future`` to provide Py3 compatibility.")
105 parser.add_option("-0", "--both-stages", action="store_true",
106 help="Apply both stages 1 and 2")
107 parser.add_option("-u", "--unicode-literals", action="store_true",
108 help="Add ``from __future__ import unicode_literals`` to i mplicitly convert all unadorned string literals '' into unicode strings")
109 parser.add_option("-f", "--fix", action="append", default=[],
110 help="Each FIX specifies a transformation; default: all.\n Either use '-f division -f metaclass' etc. or use the fully-qualified module nam e: '-f lib2to3.fixes.fix_types -f libfuturize.fixes.fix_unicode_keep_u'")
111 parser.add_option("-j", "--processes", action="store", default=1,
112 type="int", help="Run 2to3 concurrently")
113 parser.add_option("-x", "--nofix", action="append", default=[],
114 help="Prevent a fixer from being run.")
115 parser.add_option("-l", "--list-fixes", action="store_true",
116 help="List available transformations")
117 parser.add_option("-p", "--print-function", action="store_true",
118 help="Modify the grammar so that print() is a function")
119 parser.add_option("-v", "--verbose", action="store_true",
120 help="More verbose logging")
121 parser.add_option("--no-diffs", action="store_true",
122 help="Don't show diffs of the refactoring")
123 parser.add_option("-w", "--write", action="store_true",
124 help="Write back modified files")
125 parser.add_option("-n", "--nobackups", action="store_true", default=False,
126 help="Don't write backups for modified files.")
127 parser.add_option("-o", "--output-dir", action="store", type="str",
128 default="", help="Put output files in this directory "
129 "instead of overwriting the input files. Requires -n. "
130 "For Python >= 2.7 only.")
131 parser.add_option("-W", "--write-unchanged-files", action="store_true",
132 help="Also write files even if no changes were required"
133 " (useful with --output-dir); implies -w.")
134 parser.add_option("--add-suffix", action="store", type="str", default="",
135 help="Append this string to all output filenames."
136 " Requires -n if non-empty. For Python >= 2.7 only."
137 "ex: --add-suffix='3' will generate .py3 files.")
138
139 # Parse command line arguments
140 flags = {}
141 refactor_stdin = False
142 options, args = parser.parse_args(args)
143
144 if options.write_unchanged_files:
145 flags["write_unchanged_files"] = True
146 if not options.write:
147 warn("--write-unchanged-files/-W implies -w.")
148 options.write = True
149 # If we allowed these, the original files would be renamed to backup names
150 # but not replaced.
151 if options.output_dir and not options.nobackups:
152 parser.error("Can't use --output-dir/-o without -n.")
153 if options.add_suffix and not options.nobackups:
154 parser.error("Can't use --add-suffix without -n.")
155
156 if not options.write and options.no_diffs:
157 warn("not writing files and not printing diffs; that's not very useful")
158 if not options.write and options.nobackups:
159 parser.error("Can't use -n without -w")
160 if "-" in args:
161 refactor_stdin = True
162 if options.write:
163 print("Can't write to stdin.", file=sys.stderr)
164 return 2
165 # Is this ever necessary?
166 if options.print_function:
167 flags["print_function"] = True
168
169 # Set up logging handler
170 level = logging.DEBUG if options.verbose else logging.INFO
171 logging.basicConfig(format='%(name)s: %(message)s', level=level)
172 logger = logging.getLogger('libfuturize.main')
173
174 if options.stage1 or options.stage2:
175 assert options.both_stages is None
176 options.both_stages = False
177 else:
178 options.both_stages = True
179
180 avail_fixes = set()
181
182 if options.stage1 or options.both_stages:
183 avail_fixes.update(lib2to3_fix_names_stage1)
184 avail_fixes.update(libfuturize_fix_names_stage1)
185 if options.stage2 or options.both_stages:
186 avail_fixes.update(lib2to3_fix_names_stage2)
187 avail_fixes.update(libfuturize_fix_names_stage2)
188
189 if options.unicode_literals:
190 avail_fixes.add('libfuturize.fixes.fix_unicode_literals_import')
191
192 if options.version:
193 print(__version__)
194 return 0
195 if options.list_fixes:
196 print("Available transformations for the -f/--fix option:")
197 # for fixname in sorted(refactor.get_all_fix_names(fixer_pkg)):
198 for fixname in sorted(avail_fixes):
199 print(fixname)
200 if not args:
201 return 0
202 if not args:
203 print("At least one file or directory argument required.",
204 file=sys.stderr)
205 print("Use --help to show usage.", file=sys.stderr)
206 return 2
207
208 unwanted_fixes = set(fixer_pkg + ".fix_" + fix for fix in options.nofix)
209
210 extra_fixes = set()
211 if options.all_imports:
212 if options.stage1:
213 prefix = 'libfuturize.fixes.'
214 extra_fixes.add(prefix +
215 'fix_add__future__imports_except_unicode_literals')
216 else:
217 # In case the user hasn't run stage1 for some reason:
218 prefix = 'libpasteurize.fixes.'
219 extra_fixes.add(prefix + 'fix_add_all__future__imports')
220 extra_fixes.add(prefix + 'fix_add_future_standard_library_import')
221 extra_fixes.add(prefix + 'fix_add_all_future_builtins')
222 explicit = set()
223 if options.fix:
224 all_present = False
225 for fix in options.fix:
226 if fix == 'all':
227 all_present = True
228 else:
229 if ".fix_" in fix:
230 explicit.add(fix)
231 else:
232 # Infer the full module name for the fixer.
233 # First ensure that no names clash (e.g.
234 # lib2to3.fixes.fix_blah and libfuturize.fixes.fix_blah):
235 found = [f for f in avail_fixes
236 if f.endswith('fix_{0}'.format(fix))]
237 if len(found) > 1:
238 print("Ambiguous fixer name. Choose a fully qualified "
239 "module name instead from these:\n" +
240 "\n".join(" " + myf for myf in found),
241 file=sys.stderr)
242 return 2
243 elif len(found) == 0:
244 print("Unknown fixer. Use --list-fixes or -l for a list. ",
245 file=sys.stderr)
246 return 2
247 explicit.add(found[0])
248 if len(explicit & unwanted_fixes) > 0:
249 print("Conflicting usage: the following fixers have been "
250 "simultaneously requested and disallowed:\n" +
251 "\n".join(" " + myf for myf in (explicit & unwanted_fixes)),
252 file=sys.stderr)
253 return 2
254 requested = avail_fixes.union(explicit) if all_present else explicit
255 else:
256 requested = avail_fixes.union(explicit)
257 fixer_names = (requested | extra_fixes) - unwanted_fixes
258
259 input_base_dir = os.path.commonprefix(args)
260 if (input_base_dir and not input_base_dir.endswith(os.sep)
261 and not os.path.isdir(input_base_dir)):
262 # One or more similar names were passed, their directory is the base.
263 # os.path.commonprefix() is ignorant of path elements, this corrects
264 # for that weird API.
265 input_base_dir = os.path.dirname(input_base_dir)
266 if options.output_dir:
267 input_base_dir = input_base_dir.rstrip(os.sep)
268 logger.info('Output in %r will mirror the input directory %r layout.',
269 options.output_dir, input_base_dir)
270
271 # Initialize the refactoring tool
272 if future.utils.PY26:
273 extra_kwargs = {}
274 else:
275 extra_kwargs = {
276 'append_suffix': options.add_suffix,
277 'output_dir': options.output_dir,
278 'input_base_dir': input_base_dir,
279 }
280
281 rt = StdoutRefactoringTool(
282 sorted(fixer_names), flags, sorted(explicit),
283 options.nobackups, not options.no_diffs,
284 **extra_kwargs)
285
286 # Refactor all files and directories passed as arguments
287 if not rt.errors:
288 if refactor_stdin:
289 rt.refactor_stdin()
290 else:
291 try:
292 rt.refactor(args, options.write, None,
293 options.processes)
294 except refactor.MultiprocessingUnsupported:
295 assert options.processes > 1
296 print("Sorry, -j isn't " \
297 "supported on this platform.", file=sys.stderr)
298 return 1
299 rt.summarize()
300
301 # Return error status (0 if rt.errors is zero)
302 return int(bool(rt.errors))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698