1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 80 81 82 83 84 85 86 87 88 89 90 91 97 99 102 103 104 107 108 109 112 113 114 115 116 117 118 119 120 121 124 125 129 130 131 132 133 134 136 142 143 144 145 146 148 149 150 151 152 153 154 155 157 158 159 160 161 162 163 164 166 167 169 170 171 173 174 175 176 177 178 179 180 181 183 184 185 186 187 188 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 222 223 224 226 227 228 229 231 233 234 235 236 237 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 264 265 266 267 268 270 271 272 273 274 276 277 278 280 281 282 284 285 286 287 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 307 308 309 310 311 312 314 315 316 317 318 319 321 322 323 324 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 508 509 510 511 512 513 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 620 621 622 623 624 625 626 627 628 629 630 631 633 634 635 636 637 638 639 640 641 642 644 645 646 648 649 650 651 653 654 655 657 658 659 660 661 662 664 665 666 668 669 670 671 672 673 675 676 677 679 680 681 682 683 684 686 687 688 689 690 691 692 693 694 695 696 697 698 700 701 702 703 704 705 706 707 708 709 710 711 713 714 715 716 717 718 720 721 722 724 725 726 727 728 729 730 731 733 735 736 737 738 739 740 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 793 794 795 796 797 798 799 800 801 802 813 815 816 817 818 819 820 821 822 823 824 825 826 827 829 830 831 833 835 836 837 838 839 840 841 842 843 844 846 847 848 850 852 853 854 855 856 857 858 859 860 861 862 865 866 868 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 887 888 889 891 893 894 895 896 897 898 899 900 901 902 903 904 905 906 908 910 911 912 913 914 915 916 917 918 919 920 921 922 923 925 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 956 957 958 959 960 962 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 982 983 984 985 986 988 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1004 1005 1006 1007 1009 1011 1012 1013 1014 1016 1017 1018 1019 1020 1021 1023 1024 1025 1026 1028 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1044 1045 1046 1047 1048 1049 1050 1051 1053 1055 1057 1058 1059 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1098 1099 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1138 1139 1140 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1159 1160 1161 1162 1163 1164 1165 1166 1168 1169 1170 1171 1172 1173 1176 1177 1179 1180 1182 1183 1185 1186 1187 1189 1191 1192 1193 1194 1196 1201 1202 1204 1205 1217 1218 1220 1221 1224 1225 1228 1229 1231 1232 1234 1235 1236 1238 1239 1240 1241 1245 1248 1249 1250 1251 1253 1254 1255 1256 1257 1258 1259 1260 1262 1263 1264 1265 1266 1267 1268 1269 1270 1272 1273 1274 1275 1276 1277 1278 1279 1282 1283 1284 1285 1286 1287 1289 1290 1292 1293 1294 1295 1296 1297 1298 1301 1303 1304 1307 1308 1310 1315 1317 1318 1319 1320 1322 1324 1325 1328 1329 1332 1333 1336 1337 1338 1339 1341 1343 1344 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1402 1406 1408 1409 1410 1411 1412 1413 1419 1420 1425 1426 1429 1430 1432 1433 1435 1439 1441 1445 1446 1447 1448 1450 1451 1455 1456 1457 1458 1460 1461 1462 1464 1465 1466 1467 1468 1469 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1486 1488 1495 1496 1499 1500 1506 1507 1512 1514 1515 1516 1517 1519 1521 1522 1523 1524 1526 1527 1528 1529 1530 1531 1532 1534 1535 1536 1537 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1571 1572 1573 1574 1575 1576 1577 1580 1581 1582 1583 1584 1587 1595 1600 1601 1605 1606 1607 1610 1611 1613 1614 1615 1616 1617 1618 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1680 1681 1683 1685 1686 1687 1688 1691 1692 1693 1694 1695 1696 1698 1699 1700 1701 1702 1703 1705 1707 1708 1709 1712 1713 1722 1723 1725 1726 1727 1728 1731 1732 1733 1734 1736 1738 1739 1740 1741 1744 1745 1746 1747 1748 1749 1750 1751 1752 1757 1758 1760 1761 1762 1763 1764 1765 1766 1770 1774 1775 1777 1778 1781 1785 1786 1787 1788 1792 1793 1794 1795 1796 1797 1798 1801 1802 1804 1805 1808 1809 1810 1814 1815 1817 1818 1819 1820 1821 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1867 1868 1869 1874 1875 1876 1878 1879 1881 1885 1886 1887 1889 1890 1891 1892 1893 1894 1897 1898 1899 1904 1907 1908 1910 1911 1912 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1927 1928 1929 1930 1931 1933 1934 1936 1937 1939 1940 1941 1943 1944 1945 1948 1949 1950 1951 1952 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1969 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 2000 2001 2003 2006 2007 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2020 2022 2023 2026 2027 2028 2029 2030 2031 2032 2033 2034 2036 2038 2040 2041 2042 2045 2046 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2139 2140 2142 2143 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2175 2176 2178 2179 2180 2181 2183 2186 2187 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2200 2201 2202 2203 2204 2205 2206 2207 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2230 2234 2235 2236 2237 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2255 2257 2259 2260 2261 2262 2263 2264 2265 2267 2268 2269 2270 2271 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2296 2297 2298 2299 2300 2301 2302 2303 2304 2306 2307 2308 2309 2310 2312 2313 2314 2315 2317 2318 2319 2320 2322 2323 2324 2325 2326 2327 2328 2330 2331 2332 2333 2334 2335 2336 2337 2339 2340 2341 2342 2344 2345 2346 2347 2348 2349 2350 2351 2352 |
# -*- coding: utf-8 -*-
# Copyright © 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy # of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License.
This module is an optparse-inspired command-line parsing library that:
- handles both optional and positional arguments - produces highly informative usage messages - supports parsers that dispatch to sub-parsers
The following is a simple usage example that sums integers from the command-line and writes the result to a file::
parser = argparse.ArgumentParser( description='sum the integers at the command line') parser.add_argument( 'integers', metavar='int', nargs='+', type=int, help='an integer to be summed') parser.add_argument( '--log', default=sys.stdout, type=argparse.FileType('w'), help='the file where the sum should be written') args = parser.parse_args() args.log.write('%s' % sum(args.integers)) args.log.close()
The module contains the following public classes:
- ArgumentParser -- The main entry point for command-line parsing. As the example above shows, the add_argument() method is used to populate the parser with actions for optional and positional arguments. Then the parse_args() method is invoked to convert the args at the command-line into an object with attributes.
- ArgumentError -- The exception raised by ArgumentParser objects when there are errors with the parser's actions. Errors raised while parsing the command-line are caught by ArgumentParser and emitted as command-line messages.
- FileType -- A factory for defining types of files to be created. As the example above shows, instances of FileType are typically passed as the type= argument of add_argument() calls.
- Action -- The base class for parser actions. Typically actions are selected by passing strings like 'store_true' or 'append_const' to the action= argument of add_argument(). However, for greater customization of ArgumentParser actions, subclasses of Action may be defined and passed as the action= argument.
- HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter, ArgumentDefaultsHelpFormatter -- Formatter classes which may be passed as the formatter_class= argument to the ArgumentParser constructor. HelpFormatter is the default, RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser not to change the formatting for help text, and ArgumentDefaultsHelpFormatter adds information about argument defaults to the help.
All other classes in this module are considered implementation details. (Also note that HelpFormatter and RawDescriptionHelpFormatter are only considered public as object names -- the API of the formatter objects is still considered an implementation detail.) """
'ArgumentParser', 'ArgumentError', 'Namespace', 'Action', 'FileType', 'HelpFormatter', 'RawDescriptionHelpFormatter', 'RawTextHelpFormatter', 'ArgumentDefaultsHelpFormatter', ]
except NameError: from sets import Set as _set
except NameError: _basestring = str
except NameError:
def _sorted(iterable, reverse=False): result = list(iterable) result.sort() if reverse: result.reverse() return result
# silence Python 2.6 buggy warnings about Exception.message action='ignore', message='BaseException.message has been deprecated as of Python 2.6', category=DeprecationWarning, module='argparse')
# ============================= # Utility functions and classes # =============================
"""Abstract base class that provides __repr__.
The __repr__ method returns a string in the format:: ClassName(attr=name, attr=name, ...) The attributes are determined either by a class-level attribute, '_kwarg_names', or by inspecting the instance __dict__. """
type_name = type(self).__name__ arg_strings = [] for arg in self._get_args(): arg_strings.append(repr(arg)) for name, value in self._get_kwargs(): arg_strings.append('%s=%r' % (name, value)) return '%s(%s)' % (type_name, ', '.join(arg_strings))
return _sorted(self.__dict__.items())
return []
if getattr(namespace, name, None) is None: setattr(namespace, name, value) return getattr(namespace, name)
# =============== # Formatting Help # ===============
"""Formatter for generating usage messages and argument help strings.
Only the name of this class is considered a public API. All the methods provided by the class are considered an implementation detail. """
prog, indent_increment=2, max_help_position=24, width=None):
# default setting for width if width is None: try: width = int(_os.environ['COLUMNS']) except (KeyError, ValueError): width = 80 width -= 2
self._prog = prog self._indent_increment = indent_increment self._max_help_position = max_help_position self._width = width
self._current_indent = 0 self._level = 0 self._action_max_length = 0
self._root_section = self._Section(self, None) self._current_section = self._root_section
self._whitespace_matcher = _re.compile(r'\s+') self._long_break_matcher = _re.compile(r'\n\n\n+')
# =============================== # Section and indentation methods # =============================== self._current_indent += self._indent_increment self._level += 1
self._current_indent -= self._indent_increment assert self._current_indent >= 0, 'Indent decreased below 0.' self._level -= 1
self.formatter = formatter self.parent = parent self.heading = heading self.items = []
# format the indented section if self.parent is not None: self.formatter._indent() join = self.formatter._join_parts for func, args in self.items: func(*args) item_help = join([func(*args) for func, args in self.items]) if self.parent is not None: self.formatter._dedent()
# return nothing if the section was empty if not item_help: return ''
# add the heading if the section was non-empty if self.heading is not SUPPRESS and self.heading is not None: current_indent = self.formatter._current_indent heading = '%*s%s:\n' % (current_indent, '', self.heading) else: heading = ''
# join the section-initial newline, the heading and the help return join(['\n', heading, item_help, '\n'])
self._current_section.items.append((func, args))
# ======================== # Message building methods # ======================== self._indent() section = self._Section(self, self._current_section, heading) self._add_item(section.format_help, []) self._current_section = section
self._current_section = self._current_section.parent self._dedent()
if text is not SUPPRESS and text is not None: self._add_item(self._format_text, [text])
if usage is not SUPPRESS: args = usage, actions, groups, prefix self._add_item(self._format_usage, args)
if action.help is not SUPPRESS:
# find all invocations get_invocation = self._format_action_invocation invocations = [get_invocation(action)] for subaction in self._iter_indented_subactions(action): invocations.append(get_invocation(subaction))
# update the maximum item length invocation_length = max([len(s) for s in invocations]) action_length = invocation_length + self._current_indent self._action_max_length = max(self._action_max_length, action_length)
# add the item to the list self._add_item(self._format_action, [action])
for action in actions: self.add_argument(action)
# ======================= # Help-formatting methods # ======================= help = self._root_section.format_help() if help: help = self._long_break_matcher.sub('\n\n', help) help = help.strip('\n') + '\n' return help
return ''.join([part for part in part_strings if part and part is not SUPPRESS])
if prefix is None: prefix = _('usage: ')
# if usage is specified, use that if usage is not None: usage = usage % dict(prog=self._prog)
# if no optionals or positionals are available, usage is just prog elif usage is None and not actions: usage = '%(prog)s' % dict(prog=self._prog)
# if optionals and positionals are available, calculate usage elif usage is None: prog = '%(prog)s' % dict(prog=self._prog)
# split optionals from positionals optionals = [] positionals = [] for action in actions: if action.option_strings: optionals.append(action) else: positionals.append(action)
# build full usage string format = self._format_actions_usage action_usage = format(optionals + positionals, groups) usage = ' '.join([s for s in [prog, action_usage] if s])
# wrap the usage parts if it's too long text_width = self._width - self._current_indent if len(prefix) + len(usage) > text_width:
# break usage into wrappable parts part_regexp = r'\(.*?\)+|\[.*?\]+|\S+' opt_usage = format(optionals, groups) pos_usage = format(positionals, groups) opt_parts = _re.findall(part_regexp, opt_usage) pos_parts = _re.findall(part_regexp, pos_usage) assert ' '.join(opt_parts) == opt_usage assert ' '.join(pos_parts) == pos_usage
# helper for wrapping lines def get_lines(parts, indent, prefix=None): lines = [] line = [] if prefix is not None: line_len = len(prefix) - 1 else: line_len = len(indent) - 1 for part in parts: if line_len + 1 + len(part) > text_width: lines.append(indent + ' '.join(line)) line = [] line_len = len(indent) - 1 line.append(part) line_len += len(part) + 1 if line: lines.append(indent + ' '.join(line)) if prefix is not None: lines[0] = lines[0][len(indent):] return lines
# if prog is short, follow it with optionals or positionals if len(prefix) + len(prog) <= 0.75 * text_width: indent = ' ' * (len(prefix) + len(prog) + 1) if opt_parts: lines = get_lines([prog] + opt_parts, indent, prefix) lines.extend(get_lines(pos_parts, indent)) elif pos_parts: lines = get_lines([prog] + pos_parts, indent, prefix) else: lines = [prog]
# if prog is long, put it on its own line else: indent = ' ' * len(prefix) parts = opt_parts + pos_parts lines = get_lines(parts, indent) if len(lines) > 1: lines = [] lines.extend(get_lines(opt_parts, indent)) lines.extend(get_lines(pos_parts, indent)) lines = [prog] + lines
# join lines into usage usage = '\n'.join(lines)
# prefix with 'usage:' return '%s%s\n\n' % (prefix, usage)
# find group indices and identify actions in groups group_actions = _set() inserts = {} for group in groups: try: start = actions.index(group._group_actions[0]) except ValueError: continue else: end = start + len(group._group_actions) if actions[start:end] == group._group_actions: for action in group._group_actions: group_actions.add(action) if not group.required: inserts[start] = '[' inserts[end] = ']' else: inserts[start] = '(' inserts[end] = ')' for i in range(start + 1, end): inserts[i] = '|'
# collect all actions format strings parts = [] for i, action in enumerate(actions):
# suppressed arguments are marked with None # remove | separators for suppressed arguments if action.help is SUPPRESS: parts.append(None) if inserts.get(i) == '|': inserts.pop(i) elif inserts.get(i + 1) == '|': inserts.pop(i + 1)
# produce all arg strings elif not action.option_strings: part = self._format_args(action, action.dest)
# if it's in a group, strip the outer [] if action in group_actions: if part[0] == '[' and part[-1] == ']': part = part[1:-1]
# add the action string to the list parts.append(part)
# produce the first way to invoke the option in brackets else: option_string = action.option_strings[0]
# if the Optional doesn't take a value, format is: # -s or --long if action.nargs == 0: part = '%s' % option_string
# if the Optional takes a value, format is: # -s ARGS or --long ARGS else: default = action.dest.upper() args_string = self._format_args(action, default) part = '%s %s' % (option_string, args_string)
# make it look optional if it's not required or in a group if not action.required and action not in group_actions: part = '[%s]' % part
# add the action string to the list parts.append(part)
# insert things at the necessary indices for i in _sorted(inserts, reverse=True): parts[i:i] = [inserts[i]]
# join all the action items with spaces text = ' '.join([item for item in parts if item is not None])
# clean up separators for mutually exclusive groups open = r'[\[(]' close = r'[\])]' text = _re.sub(r'(%s) ' % open, r'\1', text) text = _re.sub(r' (%s)' % close, r'\1', text) text = _re.sub(r'%s *%s' % (open, close), r'', text) text = _re.sub(r'\(([^|]*)\)', r'\1', text) text = text.strip()
# return the text return text
if '%(prog)' in text: text = text % dict(prog=self._prog) text_width = self._width - self._current_indent indent = ' ' * self._current_indent return self._fill_text(text, text_width, indent) + '\n\n'
# determine the required width and the entry label help_position = min(self._action_max_length + 2, self._max_help_position) help_width = self._width - help_position action_width = help_position - self._current_indent - 2 action_header = self._format_action_invocation(action)
# ho nelp; start on same line and add a final newline if not action.help: tup = self._current_indent, '', action_header action_header = '%*s%s\n' % tup
# short action name; start on the same line and pad two spaces elif len(action_header) <= action_width: tup = self._current_indent, '', action_width, action_header action_header = '%*s%-*s ' % tup indent_first = 0
# long action name; start on the next line else: tup = self._current_indent, '', action_header action_header = '%*s%s\n' % tup indent_first = help_position
# collect the pieces of the action help parts = [action_header]
# if there was help for the action, add lines of help text if action.help: help_text = self._expand_help(action) help_lines = self._split_lines(help_text, help_width) parts.append('%*s%s\n' % (indent_first, '', help_lines[0])) for line in help_lines[1:]: parts.append('%*s%s\n' % (help_position, '', line))
# or add a newline if the description doesn't end with one elif not action_header.endswith('\n'): parts.append('\n')
# if there are any sub-actions, add their help as well for subaction in self._iter_indented_subactions(action): parts.append(self._format_action(subaction))
# return a single string return self._join_parts(parts)
if not action.option_strings: metavar, = self._metavar_formatter(action, action.dest)(1) return metavar
else: parts = []
# if the Optional doesn't take a value, format is: # -s, --long if action.nargs == 0: parts.extend(action.option_strings)
# if the Optional takes a value, format is: # -s ARGS, --long ARGS else: default = action.dest.upper() args_string = self._format_args(action, default) for option_string in action.option_strings: parts.append('%s %s' % (option_string, args_string))
return ', '.join(parts)
if action.metavar is not None: result = action.metavar elif action.choices is not None: choice_strs = [str(choice) for choice in action.choices] result = '{%s}' % ','.join(choice_strs) else: result = default_metavar
def format(tuple_size): if isinstance(result, tuple): return result else: return (result, ) * tuple_size return format
get_metavar = self._metavar_formatter(action, default_metavar) if action.nargs is None: result = '%s' % get_metavar(1) elif action.nargs == OPTIONAL: result = '[%s]' % get_metavar(1) elif action.nargs == ZERO_OR_MORE: result = '[%s [%s ...]]' % get_metavar(2) elif action.nargs == ONE_OR_MORE: result = '%s [%s ...]' % get_metavar(2) elif action.nargs == REMAINDER: result = '...' elif action.nargs == PARSER: result = '%s ...' % get_metavar(1) else: formats = ['%s' for _ in range(action.nargs)] result = ' '.join(formats) % get_metavar(action.nargs) return result
params = dict(vars(action), prog=self._prog) for name in list(params): if params[name] is SUPPRESS: del params[name] for name in list(params): if hasattr(params[name], '__name__'): params[name] = params[name].__name__ if params.get('choices') is not None: choices_str = ', '.join([str(c) for c in params['choices']]) params['choices'] = choices_str return self._get_help_string(action) % params
try: get_subactions = action._get_subactions except AttributeError: pass else: self._indent() for subaction in get_subactions(): yield subaction self._dedent()
text = self._whitespace_matcher.sub(' ', text).strip() return _textwrap.wrap(text, width)
text = self._whitespace_matcher.sub(' ', text).strip() return _textwrap.fill(text, width, initial_indent=indent, subsequent_indent=indent)
return action.help
"""Help message formatter which retains any formatting in descriptions.
Only the name of this class is considered a public API. All the methods provided by the class are considered an implementation detail. """
return ''.join([indent + line for line in text.splitlines(True)])
"""Help message formatter which retains formatting of all help text.
Only the name of this class is considered a public API. All the methods provided by the class are considered an implementation detail. """
return text.splitlines()
"""Help message formatter which adds default values to argument help.
Only the name of this class is considered a public API. All the methods provided by the class are considered an implementation detail. """
help = action.help if '%(default)' not in action.help: if action.default is not SUPPRESS: defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] if action.option_strings or action.nargs in defaulting_nargs: help += ' (default: %(default)s)' return help
# ===================== # Options and Arguments # =====================
if argument is None: return None elif argument.option_strings: return '/'.join(argument.option_strings) elif argument.metavar not in (None, SUPPRESS): return argument.metavar elif argument.dest not in (None, SUPPRESS): return argument.dest else: return None
"""An error from creating or using an argument (optional or positional).
The string value of this exception is the message, augmented with information about the argument that caused it. """
self.argument_name = _get_action_name(argument) self.message = message
if self.argument_name is None: format = '%(message)s' else: format = 'argument %(argument_name)s: %(message)s' return format % dict(message=self.message, argument_name=self.argument_name)
"""An error from trying to convert a command line string to a type."""
# ============== # Action classes # ==============
"""Information about how to convert command line strings to Python objects.
Action objects are used by an ArgumentParser to represent the information needed to parse a single argument from one or more strings from the command line. The keyword arguments to the Action constructor are also all attributes of Action instances.
Keyword Arguments:
- option_strings -- A list of command-line option strings which should be associated with this action.
- dest -- The name of the attribute to hold the created object(s)
- nargs -- The number of command-line arguments that should be consumed. By default, one argument will be consumed and a single value will be produced. Other values include: - N (an integer) consumes N arguments (and produces a list) - '?' consumes zero or one arguments - '*' consumes zero or more arguments (and produces a list) - '+' consumes one or more arguments (and produces a list) Note that the difference between the default and nargs=1 is that with the default, a single value will be produced, while with nargs=1, a list containing a single value will be produced.
- const -- The value to be produced if the option is specified and the option uses an action that takes no values.
- default -- The value to be produced if the option is not specified.
- type -- The type which the command-line arguments should be converted to, should be one of 'string', 'int', 'float', 'complex' or a callable object that accepts a single string argument. If None, 'string' is assumed.
- choices -- A container of values that should be allowed. If not None, after a command-line argument has been converted to the appropriate type, an exception will be raised if it is not a member of this collection.
- required -- True if the action must always be specified at the command line. This is only meaningful for optional command-line arguments.
- help -- The help string describing the argument.
- metavar -- The name to be used for the option's argument with the help string. If None, the 'dest' value will be used as the name. """
option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None):
names = [ 'option_strings', 'dest', 'nargs', 'const', 'default', 'type', 'choices', 'help', 'metavar', ] return [(name, getattr(self, name)) for name in names]
raise NotImplementedError(_('.__call__() not defined'))
option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None): raise ValueError('nargs for store actions must be > 0; if you ' 'have nothing to store, actions such as store ' 'true or store const may be more appropriate') raise ValueError('nargs must be %r to supply const' % OPTIONAL) option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default, type=type, choices=choices, required=required, help=help, metavar=metavar)
option_strings, dest, const, default=None, required=False, help=None, metavar=None): super(_StoreConstAction, self).__init__( option_strings=option_strings, dest=dest, nargs=0, const=const, default=default, required=required, help=help)
setattr(namespace, self.dest, self.const)
option_strings, dest, default=False, required=False, help=None): super(_StoreTrueAction, self).__init__( option_strings=option_strings, dest=dest, const=True, default=default, required=required, help=help)
option_strings, dest, default=True, required=False, help=None): super(_StoreFalseAction, self).__init__( option_strings=option_strings, dest=dest, const=False, default=default, required=required, help=help)
option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None): if nargs == 0: raise ValueError('nargs for append actions must be > 0; if arg ' 'strings are not supplying the value to append, ' 'the append const action may be more appropriate') if const is not None and nargs != OPTIONAL: raise ValueError('nargs must be %r to supply const' % OPTIONAL) super(_AppendAction, self).__init__( option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default, type=type, choices=choices, required=required, help=help, metavar=metavar)
items = _copy.copy(_ensure_value(namespace, self.dest, [])) items.append(values) setattr(namespace, self.dest, items)
option_strings, dest, const, default=None, required=False, help=None, metavar=None): super(_AppendConstAction, self).__init__( option_strings=option_strings, dest=dest, nargs=0, const=const, default=default, required=required, help=help, metavar=metavar)
items = _copy.copy(_ensure_value(namespace, self.dest, [])) items.append(self.const) setattr(namespace, self.dest, items)
option_strings, dest, default=None, required=False, help=None): super(_CountAction, self).__init__( option_strings=option_strings, dest=dest, nargs=0, default=default, required=required, help=help)
new_count = _ensure_value(namespace, self.dest, 0) + 1 setattr(namespace, self.dest, new_count)
option_strings, dest=SUPPRESS, default=SUPPRESS, help=None): option_strings=option_strings, dest=dest, default=default, nargs=0, help=help)
parser.print_help() parser.exit()
option_strings, version=None, dest=SUPPRESS, default=SUPPRESS, help=None): super(_VersionAction, self).__init__( option_strings=option_strings, dest=dest, default=default, nargs=0, help=help) self.version = version
version = self.version if version is None: version = parser.version formatter = parser._get_formatter() formatter.add_text(version) parser.exit(message=formatter.format_help())
sup = super(_SubParsersAction._ChoicesPseudoAction, self) sup.__init__(option_strings=[], dest=name, help=help)
option_strings, prog, parser_class, dest=SUPPRESS, help=None, metavar=None):
self._prog_prefix = prog self._parser_class = parser_class self._name_parser_map = {} self._choices_actions = []
super(_SubParsersAction, self).__init__( option_strings=option_strings, dest=dest, nargs=PARSER, choices=self._name_parser_map, help=help, metavar=metavar)
# set prog from the existing prefix if kwargs.get('prog') is None: kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
# create a pseudo-action to hold the choice help if 'help' in kwargs: help = kwargs.pop('help') choice_action = self._ChoicesPseudoAction(name, help) self._choices_actions.append(choice_action)
# create the parser and add it to the map parser = self._parser_class(**kwargs) self._name_parser_map[name] = parser return parser
return self._choices_actions
parser_name = values[0] arg_strings = values[1:]
# set the parser name if requested if self.dest is not SUPPRESS: setattr(namespace, self.dest, parser_name)
# select the parser try: parser = self._name_parser_map[parser_name] except KeyError: tup = parser_name, ', '.join(self._name_parser_map) msg = _('unknown parser %r (choices: %s)' % tup) raise ArgumentError(self, msg)
# parse all the remaining options into the namespace parser.parse_args(arg_strings, namespace)
# ============== # Type classes # ==============
"""Factory for creating file object types
Instances of FileType are typically passed as type= arguments to the ArgumentParser add_argument() method.
Keyword Arguments: - mode -- A string indicating how the file is to be opened. Accepts the same values as the builtin open() function. - bufsize -- The file's desired buffer size. Accepts the same values as the builtin open() function. """
self._mode = mode self._bufsize = bufsize
# the special argument "-" means sys.std{in,out} if string == '-': if 'r' in self._mode: return _sys.stdin elif 'w' in self._mode: return _sys.stdout else: msg = _('argument "-" with mode %r' % self._mode) raise ValueError(msg)
# all other arguments are used as file names if self._bufsize: return open(string, self._mode, self._bufsize) else: return open(string, self._mode)
args = [self._mode, self._bufsize] args_str = ', '.join([repr(arg) for arg in args if arg is not None]) return '%s(%s)' % (type(self).__name__, args_str)
# =========================== # Optional and Positional Parsing # ===========================
"""Simple object for storing attributes.
Implements equality by attribute names and values, and provides a simple string representation. """
setattr(self, name, kwargs[name])
return vars(self) == vars(other)
return not (self == other)
return key in self.__dict__
description, prefix_chars, argument_default, conflict_handler):
# set up registries
# register actions
# raise an exception if the conflict handler is invalid
# action storage
# groups
# defaults storage
# determines whether an "option" looks like a negative number
# whether or not there are any optionals that look like negative # numbers -- uses a list so it can be shared and edited
# ==================== # Registration methods # ====================
# ================================== # Namespace default accessor methods # ================================== self._defaults.update(kwargs)
# if these defaults match any existing arguments, replace # the previous default on the object with the new one for action in self._actions: if action.dest in kwargs: action.default = kwargs[action.dest]
for action in self._actions: if action.dest == dest and action.default is not None: return action.default return self._defaults.get(dest, None)
# ======================= # Adding argument actions # ======================= """ add_argument(dest, ..., name=value, ...) add_argument(option_string, option_string, ..., name=value, ...) """
# if no positional args are supplied or only one is supplied and # it doesn't look like an option string, parse a positional # argument if args and 'dest' in kwargs: raise ValueError('dest supplied twice for positional argument') kwargs = self._get_positional_kwargs(*args, **kwargs)
# otherwise, we're adding an optional argument else:
# if no default was supplied, use the parser-level default dest = kwargs['dest'] if dest in self._defaults: kwargs['default'] = self._defaults[dest] elif self.argument_default is not None: kwargs['default'] = self.argument_default
# create the action object, and add it to the parser raise ValueError('unknown action "%s"' % action_class)
# raise an error if the action type is not callable raise ValueError('%r is not callable' % type_func)
group = _MutuallyExclusiveGroup(self, **kwargs) self._mutually_exclusive_groups.append(group) return group
# resolve any conflicts
# add to actions list
# index the action by any option strings it has
# set the flag if any option strings look like negative numbers if not self._has_negative_number_optionals: self._has_negative_number_optionals.append(True)
# return the created action
self._actions.remove(action)
# collect groups by titles title_group_map = {} for group in self._action_groups: if group.title in title_group_map: msg = _('cannot merge actions - two groups are named %r') raise ValueError(msg % (group.title)) title_group_map[group.title] = group
# map each action to its group group_map = {} for group in container._action_groups:
# if a group with the title exists, use that, otherwise # create a new group matching the container's group if group.title not in title_group_map: title_group_map[group.title] = self.add_argument_group( title=group.title, description=group.description, conflict_handler=group.conflict_handler)
# map the actions to their new group for action in group._group_actions: group_map[action] = title_group_map[group.title]
# add container's mutually exclusive groups # NOTE: if add_mutually_exclusive_group ever gains title= and # description= then this code will need to be expanded as above for group in container._mutually_exclusive_groups: mutex_group = self.add_mutually_exclusive_group( required=group.required)
# map the actions to their new mutex group for action in group._group_actions: group_map[action] = mutex_group
# add all actions to this container or their group for action in container._actions: group_map.get(action, self)._add_action(action)
# make sure required is not specified if 'required' in kwargs: msg = _("'required' is an invalid argument for positionals") raise TypeError(msg)
# mark positional arguments as required if at least one is # always required if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]: kwargs['required'] = True if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs: kwargs['required'] = True
# return the keyword arguments with no option strings return dict(kwargs, dest=dest, option_strings=[])
# determine short and long option strings # error on strings that don't start with an appropriate prefix msg = _('invalid option string %r: ' 'must start with a character %r') tup = option_string, self.prefix_chars raise ValueError(msg % tup)
# strings starting with two prefix characters are long options
# infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' else: dest_option_string = option_strings[0] msg = _('dest= is required for options like %r') raise ValueError(msg % option_string)
# return the updated keyword arguments
# determine function from conflict handler string except AttributeError: msg = _('invalid conflict_resolution value: %r') raise ValueError(msg % self.conflict_handler)
# find all options that conflict with this option confl_optional = self._option_string_actions[option_string] confl_optionals.append((option_string, confl_optional))
# resolve any conflicts conflict_handler = self._get_handler() conflict_handler(action, confl_optionals)
message = _('conflicting option string(s): %s') conflict_string = ', '.join([option_string for option_string, action in conflicting_actions]) raise ArgumentError(action, message % conflict_string)
# remove all conflicting options for option_string, action in conflicting_actions:
# remove the conflicting option action.option_strings.remove(option_string) self._option_string_actions.pop(option_string, None)
# if the option now has no option string, remove it from the # container holding it if not action.option_strings: action.container._remove_action(action)
# add any missing keyword arguments by checking the container
# group attributes
# share most attributes with the container
def _add_action(self, action): def _remove_action(self, action): self._group_actions.remove(action)
class _MutuallyExclusiveGroup(_ArgumentGroup): def __init__(self, container, required=False): self.required = required self._container = container
def _add_action(self, action): msg = _('mutually exclusive arguments must be optional') raise ValueError(msg) action = self._container._add_action(action) self._group_actions.append(action) return action
def _remove_action(self, action): self._group_actions.remove(action)
class ArgumentParser(_AttributeHolder, _ActionsContainer):
Keyword Arguments: - prog -- The name of the program (default: sys.argv[0]) - usage -- A usage message (default: auto-generated from arguments) - description -- A description of what the program does - epilog -- Text following the argument descriptions - parents -- Parsers whose arguments should be copied into this one - formatter_class -- HelpFormatter class for printing help messages - prefix_chars -- Characters that prefix optional arguments - fromfile_prefix_chars -- Characters that prefix files containing additional arguments - argument_default -- The default value for all arguments - conflict_handler -- String indicating how to handle conflicts - add_help -- Add a -h/-help option """
def __init__(self, usage=None, description=None, epilog=None, version=None, parents=[], formatter_class=HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True):
if version is not None: warnings.warn( """The "version" argument to ArgumentParser is deprecated. """ """Please use """ """"add_argument(..., action='version', version="N", ...)" """ """instead""", DeprecationWarning)
superinit = super(ArgumentParser, self).__init__ argument_default=argument_default, conflict_handler=conflict_handler)
# default setting for prog if prog is None: self.prog = prog add_group = self.add_argument_group # register types def identity(string): # add help and version arguments if necessary # (using explicit default to override global argument_default) if self.add_help: help=_('show this help message and exit')) if self.version: '-v', '--version', action='version', default=SUPPRESS, version=self.version, help=_("show program's version number and exit"))
# add parent arguments and defaults for parent in parents: try: defaults = parent._defaults except AttributeError: pass else: self._defaults.update(defaults)
# ======================= # Pretty __repr__ methods # ======================= def _get_kwargs(self): 'prog', 'usage', 'description', 'version', 'formatter_class', 'conflict_handler', 'add_help', ] return [(name, getattr(self, name)) for name in names]
# ================================== # Optional/Positional adding methods # ================================== def add_subparsers(self, **kwargs): self.error(_('cannot have multiple subparser arguments'))
# add the parser class to the arguments if it's not present kwargs.setdefault('parser_class', type(self))
if 'title' in kwargs or 'description' in kwargs: title = _(kwargs.pop('title', 'subcommands')) description = _(kwargs.pop('description', None)) self._subparsers = self.add_argument_group(title, description) else: self._subparsers = self._positionals
# prog defaults to the usage message of this parser, skipping # optional arguments and with no "usage:" prefix if kwargs.get('prog') is None: formatter = self._get_formatter() positionals = self._get_positional_actions() groups = self._mutually_exclusive_groups formatter.add_usage(self.usage, positionals, groups, '') kwargs['prog'] = formatter.format_help().strip()
# create the parsers action and add it to the positionals list parsers_class = self._pop_action_class(kwargs, 'parsers') action = parsers_class(option_strings=[], **kwargs) self._subparsers._add_action(action)
# return the created parsers action return action
def _add_action(self, action): self._positionals._add_action(action) return action def _get_optional_actions(self): for action in self._actions if action.option_strings]
def _get_positional_actions(self): if not action.option_strings]
# ===================================== # Command line argument parsing methods # ===================================== def parse_args(self, args=None, namespace=None): if argv: msg = _('unrecognized arguments: %s') self.error(msg % ' '.join(argv)) return args
def parse_known_args(self, args=None, namespace=None): if args is None:
# default Namespace built from parser defaults if namespace is None: # add any action defaults that aren't present for action in self._actions: # add any parser defaults that aren't present for dest in self._defaults: setattr(namespace, dest, self._defaults[dest])
# parse the arguments and exit if there are any errors try: err = _sys.exc_info()[1] self.error(str(err))
def _parse_known_args(self, arg_strings, namespace): if self.fromfile_prefix_chars is not None:
# map all mutually exclusive arguments to the other arguments # they can't occur with action_conflicts = {} for i, mutex_action in enumerate(mutex_group._group_actions): conflicts = action_conflicts.setdefault(mutex_action, []) conflicts.extend(group_actions[:i]) conflicts.extend(group_actions[i + 1:])
# find all option indices, and determine the arg_string_pattern # which has an 'O' if there is an option at an index, # an 'A' if there is an argument, or a '-' if there is a '--' option_string_indices = {} # all args after -- are non-options if arg_string == '--': for arg_string in arg_strings_iter: arg_string_pattern_parts.append('A')
# otherwise, add the arg to the arg strings # and note the index if it was an option else: option_tuple = self._parse_optional(arg_string) option_string_indices[i] = option_tuple # join the pieces together to form the pattern arg_strings_pattern = ''.join(arg_string_pattern_parts) # converts arg strings to the appropriate and then takes the action seen_actions = _set() def take_action(action, argument_strings, option_string=None): # error if this argument is not allowed with other previously # seen arguments, assuming that actions that use the default # value don't really count as "present" if argument_values is not action.default: msg = _('not allowed with argument %s') action_name = _get_action_name(conflict_action) raise ArgumentError(action, msg % action_name)
# take the action if we didn't receive a SUPPRESS value # (e.g. from a default) if argument_values is not SUPPRESS: # function to convert arg_strings into an optional action def consume_optional(start_index): # get the optional identified at this index option_tuple = option_string_indices[start_index] # identify additional optionals in the same arg string # (e.g. -xyz is the same as -x -y -z if no args are required) match_argument = self._match_argument # if we found no optional action, skip it if action is None: return start_index + 1
# if there is an explicit argument, try to match the # optional's string arguments to only this if explicit_arg is not None:
# if the action is a single-dash option and takes no # arguments, try to parse more single-dash options out # of the tail of the option string chars = self.prefix_chars if arg_count == 0 and option_string[1] not in chars: action_tuples.append((action, [], option_string)) for char in self.prefix_chars: option_string = char + explicit_arg[0] explicit_arg = explicit_arg[1:] or None optionals_map = self._option_string_actions if option_string in optionals_map: action = optionals_map[option_string] break else: msg = _('ignored explicit argument %r') raise ArgumentError(action, msg % explicit_arg)
# if the action expect exactly one argument, we've # successfully matched the option; exit the loop elif arg_count == 1: stop = start_index + 1 args = [explicit_arg] action_tuples.append((action, args, option_string)) break
# error if a double-dash option did not use the # explicit argument else: msg = _('ignored explicit argument %r') raise ArgumentError(action, msg % explicit_arg)
# if there is no explicit argument, try to match the # optional's string arguments with the following strings # if successful, exit the loop else: start = start_index + 1 # add the Optional to the list and return the index at which # the Optional's string args stopped assert action_tuples # the list of Positionals left to be parsed; this is modified # by consume_positionals() positionals = self._get_positional_actions() # function to convert arg_strings into positional actions def consume_positionals(start_index): match_partial = self._match_arguments_partial # slice off the appropriate arg strings for each Positional # and add the Positional and its args to the list for action, arg_count in zip(positionals, arg_counts): start_index += arg_count take_action(action, args)
# slice off the Positionals that we just parsed and return the # index at which the Positionals' string args stopped positionals[:] = positionals[len(arg_counts):] # consume Positionals and Optionals alternately, until we have # passed the last option string extras = [] max_option_string_index = -1 # consume any Positionals preceding the next option next_option_string_index = min([ for index in option_string_indices if index >= start_index]) if start_index != next_option_string_index:
# only try to parse the next optional if we didn't consume # the option string during the positionals parsing if positionals_end_index > start_index: start_index = positionals_end_index continue else: start_index = positionals_end_index
# if we consumed all the positionals we could and we're not # at the index of an option string, there were extra arguments if start_index not in option_string_indices: extras.extend(strings) start_index = next_option_string_index
# consume the next optional and any arguments for it start_index = consume_optional(start_index) # consume any positionals following the last Optional stop_index = consume_positionals(start_index) # if we didn't consume all the argument strings, there were extras extras.extend(arg_strings[stop_index:]) # if we didn't use all the Positional objects, there were too few # arg strings supplied. if positionals:
# make sure all required actions were present for action in self._actions: name = _get_action_name(action) self.error(_('argument %s is required') % name)
# make sure all required groups had one option present for group in self._mutually_exclusive_groups: for action in group._group_actions: if action in seen_non_default_actions: break
# if no actions were used, report the error else: names = [_get_action_name(action) for action in group._group_actions if action.help is not SUPPRESS] msg = _('one of the arguments %s is required') self.error(msg % ' '.join(names))
# return the updated namespace and the extra arguments return namespace, extras def _read_args_from_files(self, arg_strings): new_arg_strings = [] for arg_string in arg_strings:
# for regular arguments, just add them back into the list if arg_string[0] not in self.fromfile_prefix_chars: new_arg_strings.append(arg_string)
# replace arguments referencing files with the file content else: try: args_file = open(arg_string[1:]) try: arg_strings = [] for arg_line in args_file.read().splitlines(): for arg in self.convert_arg_line_to_args(arg_line): arg_strings.append(arg) arg_strings = self._read_args_from_files(arg_strings) new_arg_strings.extend(arg_strings) finally: args_file.close() except IOError: err = _sys.exc_info()[1] self.error(str(err))
# return the modified argument list return new_arg_strings
def convert_arg_line_to_args(self, arg_line):
def _match_argument(self, action, arg_strings_pattern): nargs_pattern = self._get_nargs_pattern(action) # raise an exception if we weren't able to find a match if match is None: None: _('expected one argument'), OPTIONAL: _('expected at most one argument'), ONE_OR_MORE: _('expected at least one argument'), } default = _('expected %s argument(s)') % action.nargs msg = nargs_errors.get(action.nargs, default) raise ArgumentError(action, msg)
# return the number of arguments matched return len(match.group(1)) def _match_arguments_partial(self, actions, arg_strings_pattern): # final actions until we find a match result = [] pattern = ''.join([self._get_nargs_pattern(action) for action in actions_slice]) match = _re.match(pattern, arg_strings_pattern) if match is not None: result.extend([len(string) for string in match.groups()]) break
# return the list of arg string counts return result def _parse_optional(self, arg_string): if not arg_string:
# if it doesn't start with a prefix, it was meant to be positional if not arg_string[0] in self.prefix_chars: # if the option string is present in the parser, return the action if arg_string in self._option_string_actions: # if it's just a single character, it was meant to be positional if len(arg_string) == 1: return None
# if the option string before the "=" is present, return the action if '=' in arg_string: option_string, explicit_arg = arg_string.split('=', 1) if option_string in self._option_string_actions: action = self._option_string_actions[option_string] return action, option_string, explicit_arg
# search through all possible prefixes of the option string # and all actions in the parser for possible interpretations option_tuples = self._get_option_tuples(arg_string)
# if multiple actions match, the option string was ambiguous if len(option_tuples) > 1: options = ', '.join([option_string for action, option_string, explicit_arg in option_tuples]) tup = arg_string, options self.error(_('ambiguous option: %s could match %s') % tup)
# if exactly one action matched, this segmentation is good, # so return the parsed action elif len(option_tuples) == 1: option_tuple, = option_tuples return option_tuple
# if it was not found as an option, but it looks like a negative # number, it was meant to be positional # unless there are negative-number-like options if self._negative_number_matcher.match(arg_string): if not self._has_negative_number_optionals: return None
# if it contains a space, it was meant to be a positional if ' ' in arg_string: return None
# it was meant to be an optional but there is no such option # in this parser (though it might be a valid option in a subparser) return None, arg_string, None
def _get_option_tuples(self, option_string):
# option strings starting with two prefix characters are only # split at the '=' chars = self.prefix_chars if option_string[0] in chars and option_string[1] in chars: if '=' in option_string: option_prefix, explicit_arg = option_string.split('=', 1) else: option_prefix = option_string explicit_arg = None for option_string in self._option_string_actions: if option_string.startswith(option_prefix): action = self._option_string_actions[option_string] tup = action, option_string, explicit_arg result.append(tup)
# single character options can be concatenated with their arguments # but multiple character options always have to have their argument # separate elif option_string[0] in chars and option_string[1] not in chars: option_prefix = option_string explicit_arg = None short_option_prefix = option_string[:2] short_explicit_arg = option_string[2:]
for option_string in self._option_string_actions: if option_string == short_option_prefix: action = self._option_string_actions[option_string] tup = action, option_string, short_explicit_arg result.append(tup) elif option_string.startswith(option_prefix): action = self._option_string_actions[option_string] tup = action, option_string, explicit_arg result.append(tup)
# shouldn't ever get here else: self.error(_('unexpected option string: %s') % option_string)
# return the collected option tuples return result
def _get_nargs_pattern(self, action): # which are represented as '-' in the pattern nargs = action.nargs # the default (None) is assumed to be a single argument if nargs is None: # allow zero or one arguments elif nargs == OPTIONAL: nargs_pattern = '(-*A?-*)'
# allow zero or more arguments elif nargs == ZERO_OR_MORE: nargs_pattern = '(-*[A-]*)'
# allow one or more arguments elif nargs == ONE_OR_MORE: nargs_pattern = '(-*A[A-]*)'
# allow any number of options or arguments elif nargs == REMAINDER: nargs_pattern = '([-AO]*)'
# allow one argument followed by any number of options or arguments elif nargs == PARSER: nargs_pattern = '(-*A[-AO]*)'
# all others should be integers else: nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
# if this is an optional action, -- is not allowed if action.option_strings: # return the pattern return nargs_pattern # ======================== # Value conversion methods # ======================== def _get_values(self, action, arg_strings): if action.nargs not in [PARSER, REMAINDER]: # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: value = action.const else: value = action.default if isinstance(value, _basestring): value = self._get_value(action, value) self._check_value(action, value)
# when nargs='*' on a positional, if there were no command-line # args, use the default if it is anything other than None elif (not arg_strings and action.nargs == ZERO_OR_MORE and if action.default is not None: value = action.default else: value = arg_strings self._check_value(action, value)
# single argument or optional argument produces a single value elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]: # REMAINDER arguments convert all values, checking none elif action.nargs == REMAINDER: value = [self._get_value(action, v) for v in arg_strings]
# PARSER arguments convert all values, but check only the first elif action.nargs == PARSER: value = [self._get_value(action, v) for v in arg_strings] self._check_value(action, value[0])
# all other types of nargs produce a list else: value = [self._get_value(action, v) for v in arg_strings] for v in value: self._check_value(action, v)
# return the converted value return value def _get_value(self, action, arg_string): raise ArgumentError(action, msg % type_func)
# convert the value to the appropriate type try: # ArgumentTypeErrors indicate errors except ArgumentTypeError: name = getattr(action.type, '__name__', repr(action.type)) msg = str(_sys.exc_info()[1]) raise ArgumentError(action, msg)
# TypeErrors or ValueErrors also indicate errors except (TypeError, ValueError): name = getattr(action.type, '__name__', repr(action.type)) msg = _('invalid %s value: %r') raise ArgumentError(action, msg % (name, arg_string))
# return the converted value return result def _check_value(self, action, value): if action.choices is not None and value not in action.choices: msg = _('invalid choice: %r (choose from %s)') % tup raise ArgumentError(action, msg)
# ======================= # Help-formatting methods # ======================= def format_usage(self): formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups) return formatter.format_help()
def format_help(self):
# usage formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups)
# description formatter.add_text(self.description)
# positionals, optionals and user-defined groups for action_group in self._action_groups: formatter.start_section(action_group.title) formatter.add_text(action_group.description) formatter.add_arguments(action_group._group_actions) formatter.end_section()
# epilog formatter.add_text(self.epilog)
# determine help from format above return formatter.format_help()
def format_version(self): warnings.warn( 'The format_version method is deprecated -- the "version" ' 'argument to ArgumentParser is no longer supported.', DeprecationWarning) formatter = self._get_formatter() formatter.add_text(self.version) return formatter.format_help()
def _get_formatter(self):
# ===================== # Help-printing methods # ===================== def print_usage(self, file=None): file = _sys.stdout self._print_message(self.format_usage(), file)
def print_help(self, file=None): file = _sys.stdout self._print_message(self.format_help(), file)
def print_version(self, file=None): warnings.warn( 'The print_version method is deprecated -- the "version" ' 'argument to ArgumentParser is no longer supported.', DeprecationWarning) self._print_message(self.format_version(), file)
def _print_message(self, message, file=None): if file is None: file = _sys.stderr file.write(message)
# =============== # Exiting methods # =============== def exit(self, status=0, message=None): self._print_message(message, _sys.stderr) _sys.exit(status)
def error(self, message):
Prints a usage message incorporating the message to stderr and exits.
If you override this in a subclass, it should not return -- it should either exit or raise an exception. """ self.print_usage(_sys.stderr) self.exit(2, _('%s: error: %s\n') % (self.prog, message)) |