Mercurial > public > mercurial-scm > hg
comparison contrib/testparseutil.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | c2deb2512823 |
children | 127cc1f72e70 |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
12 import sys | 12 import sys |
13 | 13 |
14 #################### | 14 #################### |
15 # for Python3 compatibility (almost comes from mercurial/pycompat.py) | 15 # for Python3 compatibility (almost comes from mercurial/pycompat.py) |
16 | 16 |
17 ispy3 = (sys.version_info[0] >= 3) | 17 ispy3 = sys.version_info[0] >= 3 |
18 | |
18 | 19 |
19 def identity(a): | 20 def identity(a): |
20 return a | 21 return a |
22 | |
21 | 23 |
22 def _rapply(f, xs): | 24 def _rapply(f, xs): |
23 if xs is None: | 25 if xs is None: |
24 # assume None means non-value of optional data | 26 # assume None means non-value of optional data |
25 return xs | 27 return xs |
27 return type(xs)(_rapply(f, x) for x in xs) | 29 return type(xs)(_rapply(f, x) for x in xs) |
28 if isinstance(xs, dict): | 30 if isinstance(xs, dict): |
29 return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items()) | 31 return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items()) |
30 return f(xs) | 32 return f(xs) |
31 | 33 |
34 | |
32 def rapply(f, xs): | 35 def rapply(f, xs): |
33 if f is identity: | 36 if f is identity: |
34 # fast path mainly for py2 | 37 # fast path mainly for py2 |
35 return xs | 38 return xs |
36 return _rapply(f, xs) | 39 return _rapply(f, xs) |
37 | 40 |
41 | |
38 if ispy3: | 42 if ispy3: |
39 import builtins | 43 import builtins |
40 | 44 |
41 def bytestr(s): | 45 def bytestr(s): |
42 # tiny version of pycompat.bytestr | 46 # tiny version of pycompat.bytestr |
47 return s | 51 return s |
48 return s.decode(u'latin-1') | 52 return s.decode(u'latin-1') |
49 | 53 |
50 def opentext(f): | 54 def opentext(f): |
51 return open(f, 'r') | 55 return open(f, 'r') |
56 | |
57 | |
52 else: | 58 else: |
53 bytestr = str | 59 bytestr = str |
54 sysstr = identity | 60 sysstr = identity |
55 | 61 |
56 opentext = open | 62 opentext = open |
57 | 63 |
64 | |
58 def b2s(x): | 65 def b2s(x): |
59 # convert BYTES elements in "x" to SYSSTR recursively | 66 # convert BYTES elements in "x" to SYSSTR recursively |
60 return rapply(sysstr, x) | 67 return rapply(sysstr, x) |
61 | 68 |
69 | |
62 def writeout(data): | 70 def writeout(data): |
63 # write "data" in BYTES into stdout | 71 # write "data" in BYTES into stdout |
64 sys.stdout.write(data) | 72 sys.stdout.write(data) |
65 | 73 |
74 | |
66 def writeerr(data): | 75 def writeerr(data): |
67 # write "data" in BYTES into stderr | 76 # write "data" in BYTES into stderr |
68 sys.stderr.write(data) | 77 sys.stderr.write(data) |
69 | 78 |
79 | |
70 #################### | 80 #################### |
81 | |
71 | 82 |
72 class embeddedmatcher(object): | 83 class embeddedmatcher(object): |
73 """Base class to detect embedded code fragments in *.t test script | 84 """Base class to detect embedded code fragments in *.t test script |
74 """ | 85 """ |
86 | |
75 __metaclass__ = abc.ABCMeta | 87 __metaclass__ = abc.ABCMeta |
76 | 88 |
77 def __init__(self, desc): | 89 def __init__(self, desc): |
78 self.desc = desc | 90 self.desc = desc |
79 | 91 |
123 """ | 135 """ |
124 | 136 |
125 @abc.abstractmethod | 137 @abc.abstractmethod |
126 def codeinside(self, ctx, line): | 138 def codeinside(self, ctx, line): |
127 """Return actual code at line inside embedded code""" | 139 """Return actual code at line inside embedded code""" |
140 | |
128 | 141 |
129 def embedded(basefile, lines, errors, matchers): | 142 def embedded(basefile, lines, errors, matchers): |
130 """pick embedded code fragments up from given lines | 143 """pick embedded code fragments up from given lines |
131 | 144 |
132 This is common parsing logic, which examines specified matchers on | 145 This is common parsing logic, which examines specified matchers on |
166 >>> b2s(errors) | 179 >>> b2s(errors) |
167 ['<dummy>:1: ambiguous line for "ambiguous #1", "ambiguous #2"'] | 180 ['<dummy>:1: ambiguous line for "ambiguous #1", "ambiguous #2"'] |
168 | 181 |
169 """ | 182 """ |
170 matcher = None | 183 matcher = None |
171 ctx = filename = code = startline = None # for pyflakes | 184 ctx = filename = code = startline = None # for pyflakes |
172 | 185 |
173 for lineno, line in enumerate(lines, 1): | 186 for lineno, line in enumerate(lines, 1): |
174 if not line.endswith('\n'): | 187 if not line.endswith('\n'): |
175 line += '\n' # to normalize EOF line | 188 line += '\n' # to normalize EOF line |
176 if matcher: # now, inside embedded code | 189 if matcher: # now, inside embedded code |
177 if matcher.endsat(ctx, line): | 190 if matcher.endsat(ctx, line): |
178 codeatend = matcher.codeatend(ctx, line) | 191 codeatend = matcher.codeatend(ctx, line) |
179 if codeatend is not None: | 192 if codeatend is not None: |
180 code.append(codeatend) | 193 code.append(codeatend) |
181 if not matcher.ignores(ctx): | 194 if not matcher.ignores(ctx): |
183 matcher = None | 196 matcher = None |
184 # DO NOT "continue", because line might start next fragment | 197 # DO NOT "continue", because line might start next fragment |
185 elif not matcher.isinside(ctx, line): | 198 elif not matcher.isinside(ctx, line): |
186 # this is an error of basefile | 199 # this is an error of basefile |
187 # (if matchers are implemented correctly) | 200 # (if matchers are implemented correctly) |
188 errors.append('%s:%d: unexpected line for "%s"' | 201 errors.append( |
189 % (basefile, lineno, matcher.desc)) | 202 '%s:%d: unexpected line for "%s"' |
203 % (basefile, lineno, matcher.desc) | |
204 ) | |
190 # stop extracting embedded code by current 'matcher', | 205 # stop extracting embedded code by current 'matcher', |
191 # because appearance of unexpected line might mean | 206 # because appearance of unexpected line might mean |
192 # that expected end-of-embedded-code line might never | 207 # that expected end-of-embedded-code line might never |
193 # appear | 208 # appear |
194 matcher = None | 209 matcher = None |
206 if ctx: | 221 if ctx: |
207 matched.append((m, ctx)) | 222 matched.append((m, ctx)) |
208 if matched: | 223 if matched: |
209 if len(matched) > 1: | 224 if len(matched) > 1: |
210 # this is an error of matchers, maybe | 225 # this is an error of matchers, maybe |
211 errors.append('%s:%d: ambiguous line for %s' % | 226 errors.append( |
212 (basefile, lineno, | 227 '%s:%d: ambiguous line for %s' |
213 ', '.join(['"%s"' % m.desc | 228 % ( |
214 for m, c in matched]))) | 229 basefile, |
230 lineno, | |
231 ', '.join(['"%s"' % m.desc for m, c in matched]), | |
232 ) | |
233 ) | |
215 # omit extracting embedded code, because choosing | 234 # omit extracting embedded code, because choosing |
216 # arbitrary matcher from matched ones might fail to | 235 # arbitrary matcher from matched ones might fail to |
217 # detect the end of embedded code as expected. | 236 # detect the end of embedded code as expected. |
218 continue | 237 continue |
219 matcher, ctx = matched[0] | 238 matcher, ctx = matched[0] |
236 if not matcher.ignores(ctx): | 255 if not matcher.ignores(ctx): |
237 yield (filename, startline, lineno + 1, ''.join(code)) | 256 yield (filename, startline, lineno + 1, ''.join(code)) |
238 else: | 257 else: |
239 # this is an error of basefile | 258 # this is an error of basefile |
240 # (if matchers are implemented correctly) | 259 # (if matchers are implemented correctly) |
241 errors.append('%s:%d: unexpected end of file for "%s"' | 260 errors.append( |
242 % (basefile, lineno, matcher.desc)) | 261 '%s:%d: unexpected end of file for "%s"' |
262 % (basefile, lineno, matcher.desc) | |
263 ) | |
264 | |
243 | 265 |
244 # heredoc limit mark to ignore embedded code at check-code.py or so | 266 # heredoc limit mark to ignore embedded code at check-code.py or so |
245 heredocignorelimit = 'NO_CHECK_EOF' | 267 heredocignorelimit = 'NO_CHECK_EOF' |
246 | 268 |
247 # the pattern to match against cases below, and to return a limit mark | 269 # the pattern to match against cases below, and to return a limit mark |
249 # | 271 # |
250 # - << LIMITMARK | 272 # - << LIMITMARK |
251 # - << "LIMITMARK" | 273 # - << "LIMITMARK" |
252 # - << 'LIMITMARK' | 274 # - << 'LIMITMARK' |
253 heredoclimitpat = r'\s*<<\s*(?P<lquote>["\']?)(?P<limit>\w+)(?P=lquote)' | 275 heredoclimitpat = r'\s*<<\s*(?P<lquote>["\']?)(?P<limit>\w+)(?P=lquote)' |
276 | |
254 | 277 |
255 class fileheredocmatcher(embeddedmatcher): | 278 class fileheredocmatcher(embeddedmatcher): |
256 """Detect "cat > FILE << LIMIT" style embedded code | 279 """Detect "cat > FILE << LIMIT" style embedded code |
257 | 280 |
258 >>> matcher = fileheredocmatcher('heredoc .py file', r'[^<]+\\.py') | 281 >>> matcher = fileheredocmatcher('heredoc .py file', r'[^<]+\\.py') |
288 False | 311 False |
289 >>> ctx = matcher.startsat(' $ cat > file.py << NO_CHECK_EOF\\n') | 312 >>> ctx = matcher.startsat(' $ cat > file.py << NO_CHECK_EOF\\n') |
290 >>> matcher.ignores(ctx) | 313 >>> matcher.ignores(ctx) |
291 True | 314 True |
292 """ | 315 """ |
316 | |
293 _prefix = ' > ' | 317 _prefix = ' > ' |
294 | 318 |
295 def __init__(self, desc, namepat): | 319 def __init__(self, desc, namepat): |
296 super(fileheredocmatcher, self).__init__(desc) | 320 super(fileheredocmatcher, self).__init__(desc) |
297 | 321 |
300 # group | 324 # group |
301 # | 325 # |
302 # - > NAMEPAT | 326 # - > NAMEPAT |
303 # - > "NAMEPAT" | 327 # - > "NAMEPAT" |
304 # - > 'NAMEPAT' | 328 # - > 'NAMEPAT' |
305 namepat = (r'\s*>>?\s*(?P<nquote>["\']?)(?P<name>%s)(?P=nquote)' | 329 namepat = ( |
306 % namepat) | 330 r'\s*>>?\s*(?P<nquote>["\']?)(?P<name>%s)(?P=nquote)' % namepat |
331 ) | |
307 self._fileres = [ | 332 self._fileres = [ |
308 # "cat > NAME << LIMIT" case | 333 # "cat > NAME << LIMIT" case |
309 re.compile(r' \$ \s*cat' + namepat + heredoclimitpat), | 334 re.compile(r' \$ \s*cat' + namepat + heredoclimitpat), |
310 # "cat << LIMIT > NAME" case | 335 # "cat << LIMIT > NAME" case |
311 re.compile(r' \$ \s*cat' + heredoclimitpat + namepat), | 336 re.compile(r' \$ \s*cat' + heredoclimitpat + namepat), |
314 def startsat(self, line): | 339 def startsat(self, line): |
315 # ctx is (filename, END-LINE-OF-EMBEDDED-CODE) tuple | 340 # ctx is (filename, END-LINE-OF-EMBEDDED-CODE) tuple |
316 for filere in self._fileres: | 341 for filere in self._fileres: |
317 matched = filere.match(line) | 342 matched = filere.match(line) |
318 if matched: | 343 if matched: |
319 return (matched.group('name'), | 344 return ( |
320 ' > %s\n' % matched.group('limit')) | 345 matched.group('name'), |
346 ' > %s\n' % matched.group('limit'), | |
347 ) | |
321 | 348 |
322 def endsat(self, ctx, line): | 349 def endsat(self, ctx, line): |
323 return ctx[1] == line | 350 return ctx[1] == line |
324 | 351 |
325 def isinside(self, ctx, line): | 352 def isinside(self, ctx, line): |
330 | 357 |
331 def filename(self, ctx): | 358 def filename(self, ctx): |
332 return ctx[0] | 359 return ctx[0] |
333 | 360 |
334 def codeatstart(self, ctx, line): | 361 def codeatstart(self, ctx, line): |
335 return None # no embedded code at start line | 362 return None # no embedded code at start line |
336 | 363 |
337 def codeatend(self, ctx, line): | 364 def codeatend(self, ctx, line): |
338 return None # no embedded code at end line | 365 return None # no embedded code at end line |
339 | 366 |
340 def codeinside(self, ctx, line): | 367 def codeinside(self, ctx, line): |
341 return line[len(self._prefix):] # strip prefix | 368 return line[len(self._prefix) :] # strip prefix |
369 | |
342 | 370 |
343 #### | 371 #### |
344 # for embedded python script | 372 # for embedded python script |
373 | |
345 | 374 |
346 class pydoctestmatcher(embeddedmatcher): | 375 class pydoctestmatcher(embeddedmatcher): |
347 """Detect ">>> code" style embedded python code | 376 """Detect ">>> code" style embedded python code |
348 | 377 |
349 >>> matcher = pydoctestmatcher() | 378 >>> matcher = pydoctestmatcher() |
393 >>> end = '\\n' | 422 >>> end = '\\n' |
394 >>> matcher.endsat(ctx, end) | 423 >>> matcher.endsat(ctx, end) |
395 True | 424 True |
396 >>> matcher.codeatend(ctx, end) | 425 >>> matcher.codeatend(ctx, end) |
397 """ | 426 """ |
427 | |
398 _prefix = ' >>> ' | 428 _prefix = ' >>> ' |
399 _prefixre = re.compile(r' (>>>|\.\.\.) ') | 429 _prefixre = re.compile(r' (>>>|\.\.\.) ') |
400 | 430 |
401 # If a line matches against not _prefixre but _outputre, that line | 431 # If a line matches against not _prefixre but _outputre, that line |
402 # is "an expected output line" (= not a part of code fragment). | 432 # is "an expected output line" (= not a part of code fragment). |
417 | 447 |
418 def endsat(self, ctx, line): | 448 def endsat(self, ctx, line): |
419 return not (self._prefixre.match(line) or self._outputre.match(line)) | 449 return not (self._prefixre.match(line) or self._outputre.match(line)) |
420 | 450 |
421 def isinside(self, ctx, line): | 451 def isinside(self, ctx, line): |
422 return True # always true, if not yet ended | 452 return True # always true, if not yet ended |
423 | 453 |
424 def ignores(self, ctx): | 454 def ignores(self, ctx): |
425 return False # should be checked always | 455 return False # should be checked always |
426 | 456 |
427 def filename(self, ctx): | 457 def filename(self, ctx): |
428 return None # no filename | 458 return None # no filename |
429 | 459 |
430 def codeatstart(self, ctx, line): | 460 def codeatstart(self, ctx, line): |
431 return line[len(self._prefix):] # strip prefix ' >>> '/' ... ' | 461 return line[len(self._prefix) :] # strip prefix ' >>> '/' ... ' |
432 | 462 |
433 def codeatend(self, ctx, line): | 463 def codeatend(self, ctx, line): |
434 return None # no embedded code at end line | 464 return None # no embedded code at end line |
435 | 465 |
436 def codeinside(self, ctx, line): | 466 def codeinside(self, ctx, line): |
437 if self._prefixre.match(line): | 467 if self._prefixre.match(line): |
438 return line[len(self._prefix):] # strip prefix ' >>> '/' ... ' | 468 return line[len(self._prefix) :] # strip prefix ' >>> '/' ... ' |
439 return '\n' # an expected output line is treated as an empty line | 469 return '\n' # an expected output line is treated as an empty line |
470 | |
440 | 471 |
441 class pyheredocmatcher(embeddedmatcher): | 472 class pyheredocmatcher(embeddedmatcher): |
442 """Detect "python << LIMIT" style embedded python code | 473 """Detect "python << LIMIT" style embedded python code |
443 | 474 |
444 >>> matcher = pyheredocmatcher() | 475 >>> matcher = pyheredocmatcher() |
472 False | 503 False |
473 >>> ctx = matcher.startsat(' $ python << NO_CHECK_EOF\\n') | 504 >>> ctx = matcher.startsat(' $ python << NO_CHECK_EOF\\n') |
474 >>> matcher.ignores(ctx) | 505 >>> matcher.ignores(ctx) |
475 True | 506 True |
476 """ | 507 """ |
508 | |
477 _prefix = ' > ' | 509 _prefix = ' > ' |
478 | 510 |
479 _startre = re.compile(r' \$ (\$PYTHON|"\$PYTHON"|python).*' + | 511 _startre = re.compile( |
480 heredoclimitpat) | 512 r' \$ (\$PYTHON|"\$PYTHON"|python).*' + heredoclimitpat |
513 ) | |
481 | 514 |
482 def __init__(self): | 515 def __init__(self): |
483 super(pyheredocmatcher, self).__init__("heredoc python invocation") | 516 super(pyheredocmatcher, self).__init__("heredoc python invocation") |
484 | 517 |
485 def startsat(self, line): | 518 def startsat(self, line): |
496 | 529 |
497 def ignores(self, ctx): | 530 def ignores(self, ctx): |
498 return ' > %s\n' % heredocignorelimit == ctx | 531 return ' > %s\n' % heredocignorelimit == ctx |
499 | 532 |
500 def filename(self, ctx): | 533 def filename(self, ctx): |
501 return None # no filename | 534 return None # no filename |
502 | 535 |
503 def codeatstart(self, ctx, line): | 536 def codeatstart(self, ctx, line): |
504 return None # no embedded code at start line | 537 return None # no embedded code at start line |
505 | 538 |
506 def codeatend(self, ctx, line): | 539 def codeatend(self, ctx, line): |
507 return None # no embedded code at end line | 540 return None # no embedded code at end line |
508 | 541 |
509 def codeinside(self, ctx, line): | 542 def codeinside(self, ctx, line): |
510 return line[len(self._prefix):] # strip prefix | 543 return line[len(self._prefix) :] # strip prefix |
544 | |
511 | 545 |
512 _pymatchers = [ | 546 _pymatchers = [ |
513 pydoctestmatcher(), | 547 pydoctestmatcher(), |
514 pyheredocmatcher(), | 548 pyheredocmatcher(), |
515 # use '[^<]+' instead of '\S+', in order to match against | 549 # use '[^<]+' instead of '\S+', in order to match against |
516 # paths including whitespaces | 550 # paths including whitespaces |
517 fileheredocmatcher('heredoc .py file', r'[^<]+\.py'), | 551 fileheredocmatcher('heredoc .py file', r'[^<]+\.py'), |
518 ] | 552 ] |
519 | 553 |
554 | |
520 def pyembedded(basefile, lines, errors): | 555 def pyembedded(basefile, lines, errors): |
521 return embedded(basefile, lines, errors, _pymatchers) | 556 return embedded(basefile, lines, errors, _pymatchers) |
557 | |
522 | 558 |
523 #### | 559 #### |
524 # for embedded shell script | 560 # for embedded shell script |
525 | 561 |
526 _shmatchers = [ | 562 _shmatchers = [ |
527 # use '[^<]+' instead of '\S+', in order to match against | 563 # use '[^<]+' instead of '\S+', in order to match against |
528 # paths including whitespaces | 564 # paths including whitespaces |
529 fileheredocmatcher('heredoc .sh file', r'[^<]+\.sh'), | 565 fileheredocmatcher('heredoc .sh file', r'[^<]+\.sh'), |
530 ] | 566 ] |
531 | 567 |
568 | |
532 def shembedded(basefile, lines, errors): | 569 def shembedded(basefile, lines, errors): |
533 return embedded(basefile, lines, errors, _shmatchers) | 570 return embedded(basefile, lines, errors, _shmatchers) |
571 | |
534 | 572 |
535 #### | 573 #### |
536 # for embedded hgrc configuration | 574 # for embedded hgrc configuration |
537 | 575 |
538 _hgrcmatchers = [ | 576 _hgrcmatchers = [ |
539 # use '[^<]+' instead of '\S+', in order to match against | 577 # use '[^<]+' instead of '\S+', in order to match against |
540 # paths including whitespaces | 578 # paths including whitespaces |
541 fileheredocmatcher('heredoc hgrc file', | 579 fileheredocmatcher( |
542 r'(([^/<]+/)+hgrc|\$HGRCPATH|\${HGRCPATH})'), | 580 'heredoc hgrc file', r'(([^/<]+/)+hgrc|\$HGRCPATH|\${HGRCPATH})' |
581 ), | |
543 ] | 582 ] |
583 | |
544 | 584 |
545 def hgrcembedded(basefile, lines, errors): | 585 def hgrcembedded(basefile, lines, errors): |
546 return embedded(basefile, lines, errors, _hgrcmatchers) | 586 return embedded(basefile, lines, errors, _hgrcmatchers) |
587 | |
547 | 588 |
548 #### | 589 #### |
549 | 590 |
550 if __name__ == "__main__": | 591 if __name__ == "__main__": |
551 import optparse | 592 import optparse |
556 for name, starts, ends, code in embeddedfunc(basefile, lines, errors): | 597 for name, starts, ends, code in embeddedfunc(basefile, lines, errors): |
557 if not name: | 598 if not name: |
558 name = '<anonymous>' | 599 name = '<anonymous>' |
559 writeout("%s:%d: %s starts\n" % (basefile, starts, name)) | 600 writeout("%s:%d: %s starts\n" % (basefile, starts, name)) |
560 if opts.verbose and code: | 601 if opts.verbose and code: |
561 writeout(" |%s\n" % | 602 writeout(" |%s\n" % "\n |".join(l for l in code.splitlines())) |
562 "\n |".join(l for l in code.splitlines())) | |
563 writeout("%s:%d: %s ends\n" % (basefile, ends, name)) | 603 writeout("%s:%d: %s ends\n" % (basefile, ends, name)) |
564 for e in errors: | 604 for e in errors: |
565 writeerr("%s\n" % e) | 605 writeerr("%s\n" % e) |
566 return len(errors) | 606 return len(errors) |
567 | 607 |
577 if showembedded('<stdin>', lines, embeddedfunc, opts): | 617 if showembedded('<stdin>', lines, embeddedfunc, opts): |
578 ret = 1 | 618 ret = 1 |
579 return ret | 619 return ret |
580 | 620 |
581 commands = {} | 621 commands = {} |
622 | |
582 def command(name, desc): | 623 def command(name, desc): |
583 def wrap(func): | 624 def wrap(func): |
584 commands[name] = (desc, func) | 625 commands[name] = (desc, func) |
626 | |
585 return wrap | 627 return wrap |
586 | 628 |
587 @command("pyembedded", "detect embedded python script") | 629 @command("pyembedded", "detect embedded python script") |
588 def pyembeddedcmd(args, opts): | 630 def pyembeddedcmd(args, opts): |
589 return applyembedded(args, pyembedded, opts) | 631 return applyembedded(args, pyembedded, opts) |
594 | 636 |
595 @command("hgrcembedded", "detect embedded hgrc configuration") | 637 @command("hgrcembedded", "detect embedded hgrc configuration") |
596 def hgrcembeddedcmd(args, opts): | 638 def hgrcembeddedcmd(args, opts): |
597 return applyembedded(args, hgrcembedded, opts) | 639 return applyembedded(args, hgrcembedded, opts) |
598 | 640 |
599 availablecommands = "\n".join([" - %s: %s" % (key, value[0]) | 641 availablecommands = "\n".join( |
600 for key, value in commands.items()]) | 642 [" - %s: %s" % (key, value[0]) for key, value in commands.items()] |
601 | 643 ) |
602 parser = optparse.OptionParser("""%prog COMMAND [file ...] | 644 |
645 parser = optparse.OptionParser( | |
646 """%prog COMMAND [file ...] | |
603 | 647 |
604 Pick up embedded code fragments from given file(s) or stdin, and list | 648 Pick up embedded code fragments from given file(s) or stdin, and list |
605 up start/end lines of them in standard compiler format | 649 up start/end lines of them in standard compiler format |
606 ("FILENAME:LINENO:"). | 650 ("FILENAME:LINENO:"). |
607 | 651 |
608 Available commands are: | 652 Available commands are: |
609 """ + availablecommands + """ | 653 """ |
610 """) | 654 + availablecommands |
611 parser.add_option("-v", "--verbose", | 655 + """ |
612 help="enable additional output (e.g. actual code)", | 656 """ |
613 action="store_true") | 657 ) |
658 parser.add_option( | |
659 "-v", | |
660 "--verbose", | |
661 help="enable additional output (e.g. actual code)", | |
662 action="store_true", | |
663 ) | |
614 (opts, args) = parser.parse_args() | 664 (opts, args) = parser.parse_args() |
615 | 665 |
616 if not args or args[0] not in commands: | 666 if not args or args[0] not in commands: |
617 parser.print_help() | 667 parser.print_help() |
618 sys.exit(255) | 668 sys.exit(255) |