Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/libfuturize/main.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
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 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 on ``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 implicitly 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.\nEither use '-f division -f metaclass' etc. or use the fully-qualified module name: '-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() | |
209 for fix in options.nofix: | |
210 if ".fix_" in fix: | |
211 unwanted_fixes.add(fix) | |
212 else: | |
213 # Infer the full module name for the fixer. | |
214 # First ensure that no names clash (e.g. | |
215 # lib2to3.fixes.fix_blah and libfuturize.fixes.fix_blah): | |
216 found = [f for f in avail_fixes | |
217 if f.endswith('fix_{0}'.format(fix))] | |
218 if len(found) > 1: | |
219 print("Ambiguous fixer name. Choose a fully qualified " | |
220 "module name instead from these:\n" + | |
221 "\n".join(" " + myf for myf in found), | |
222 file=sys.stderr) | |
223 return 2 | |
224 elif len(found) == 0: | |
225 print("Unknown fixer. Use --list-fixes or -l for a list.", | |
226 file=sys.stderr) | |
227 return 2 | |
228 unwanted_fixes.add(found[0]) | |
229 | |
230 extra_fixes = set() | |
231 if options.all_imports: | |
232 if options.stage1: | |
233 prefix = 'libfuturize.fixes.' | |
234 extra_fixes.add(prefix + | |
235 'fix_add__future__imports_except_unicode_literals') | |
236 else: | |
237 # In case the user hasn't run stage1 for some reason: | |
238 prefix = 'libpasteurize.fixes.' | |
239 extra_fixes.add(prefix + 'fix_add_all__future__imports') | |
240 extra_fixes.add(prefix + 'fix_add_future_standard_library_import') | |
241 extra_fixes.add(prefix + 'fix_add_all_future_builtins') | |
242 explicit = set() | |
243 if options.fix: | |
244 all_present = False | |
245 for fix in options.fix: | |
246 if fix == 'all': | |
247 all_present = True | |
248 else: | |
249 if ".fix_" in fix: | |
250 explicit.add(fix) | |
251 else: | |
252 # Infer the full module name for the fixer. | |
253 # First ensure that no names clash (e.g. | |
254 # lib2to3.fixes.fix_blah and libfuturize.fixes.fix_blah): | |
255 found = [f for f in avail_fixes | |
256 if f.endswith('fix_{0}'.format(fix))] | |
257 if len(found) > 1: | |
258 print("Ambiguous fixer name. Choose a fully qualified " | |
259 "module name instead from these:\n" + | |
260 "\n".join(" " + myf for myf in found), | |
261 file=sys.stderr) | |
262 return 2 | |
263 elif len(found) == 0: | |
264 print("Unknown fixer. Use --list-fixes or -l for a list.", | |
265 file=sys.stderr) | |
266 return 2 | |
267 explicit.add(found[0]) | |
268 if len(explicit & unwanted_fixes) > 0: | |
269 print("Conflicting usage: the following fixers have been " | |
270 "simultaneously requested and disallowed:\n" + | |
271 "\n".join(" " + myf for myf in (explicit & unwanted_fixes)), | |
272 file=sys.stderr) | |
273 return 2 | |
274 requested = avail_fixes.union(explicit) if all_present else explicit | |
275 else: | |
276 requested = avail_fixes.union(explicit) | |
277 fixer_names = (requested | extra_fixes) - unwanted_fixes | |
278 | |
279 input_base_dir = os.path.commonprefix(args) | |
280 if (input_base_dir and not input_base_dir.endswith(os.sep) | |
281 and not os.path.isdir(input_base_dir)): | |
282 # One or more similar names were passed, their directory is the base. | |
283 # os.path.commonprefix() is ignorant of path elements, this corrects | |
284 # for that weird API. | |
285 input_base_dir = os.path.dirname(input_base_dir) | |
286 if options.output_dir: | |
287 input_base_dir = input_base_dir.rstrip(os.sep) | |
288 logger.info('Output in %r will mirror the input directory %r layout.', | |
289 options.output_dir, input_base_dir) | |
290 | |
291 # Initialize the refactoring tool | |
292 if future.utils.PY26: | |
293 extra_kwargs = {} | |
294 else: | |
295 extra_kwargs = { | |
296 'append_suffix': options.add_suffix, | |
297 'output_dir': options.output_dir, | |
298 'input_base_dir': input_base_dir, | |
299 } | |
300 | |
301 rt = StdoutRefactoringTool( | |
302 sorted(fixer_names), flags, sorted(explicit), | |
303 options.nobackups, not options.no_diffs, | |
304 **extra_kwargs) | |
305 | |
306 # Refactor all files and directories passed as arguments | |
307 if not rt.errors: | |
308 if refactor_stdin: | |
309 rt.refactor_stdin() | |
310 else: | |
311 try: | |
312 rt.refactor(args, options.write, None, | |
313 options.processes) | |
314 except refactor.MultiprocessingUnsupported: | |
315 assert options.processes > 1 | |
316 print("Sorry, -j isn't " \ | |
317 "supported on this platform.", file=sys.stderr) | |
318 return 1 | |
319 rt.summarize() | |
320 | |
321 # Return error status (0 if rt.errors is zero) | |
322 return int(bool(rt.errors)) |