1#!/usr/bin/env python3 2# 3# Argument Clinic 4# Copyright 2012-2013 by Larry Hastings. 5# Licensed to the PSF under a contributor agreement. 6# 7 8import abc 9import ast 10import collections 11import contextlib 12import copy 13import cpp 14import functools 15import hashlib 16import inspect 17import io 18import itertools 19import os 20import pprint 21import re 22import shlex 23import string 24import sys 25import tempfile 26import textwrap 27import traceback 28import types 29 30from types import * 31NoneType = type(None) 32 33# TODO: 34# 35# soon: 36# 37# * allow mixing any two of {positional-only, positional-or-keyword, 38# keyword-only} 39# * dict constructor uses positional-only and keyword-only 40# * max and min use positional only with an optional group 41# and keyword-only 42# 43 44version = '1' 45 46NoneType = type(None) 47 48class Unspecified: 49 def __repr__(self): 50 return '<Unspecified>' 51 52unspecified = Unspecified() 53 54 55class Null: 56 def __repr__(self): 57 return '<Null>' 58 59NULL = Null() 60 61 62class Unknown: 63 def __repr__(self): 64 return '<Unknown>' 65 66unknown = Unknown() 67 68sig_end_marker = '--' 69 70 71_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output") 72 73def _text_accumulator(): 74 text = [] 75 def output(): 76 s = ''.join(text) 77 text.clear() 78 return s 79 return _text_accumulator_nt(text, text.append, output) 80 81 82text_accumulator_nt = collections.namedtuple("text_accumulator", "text append") 83 84def text_accumulator(): 85 """ 86 Creates a simple text accumulator / joiner. 87 88 Returns a pair of callables: 89 append, output 90 "append" appends a string to the accumulator. 91 "output" returns the contents of the accumulator 92 joined together (''.join(accumulator)) and 93 empties the accumulator. 94 """ 95 text, append, output = _text_accumulator() 96 return text_accumulator_nt(append, output) 97 98 99def warn_or_fail(fail=False, *args, filename=None, line_number=None): 100 joined = " ".join([str(a) for a in args]) 101 add, output = text_accumulator() 102 if fail: 103 add("Error") 104 else: 105 add("Warning") 106 if clinic: 107 if filename is None: 108 filename = clinic.filename 109 if getattr(clinic, 'block_parser', None) and (line_number is None): 110 line_number = clinic.block_parser.line_number 111 if filename is not None: 112 add(' in file "' + filename + '"') 113 if line_number is not None: 114 add(" on line " + str(line_number)) 115 add(':\n') 116 add(joined) 117 print(output()) 118 if fail: 119 sys.exit(-1) 120 121 122def warn(*args, filename=None, line_number=None): 123 return warn_or_fail(False, *args, filename=filename, line_number=line_number) 124 125def fail(*args, filename=None, line_number=None): 126 return warn_or_fail(True, *args, filename=filename, line_number=line_number) 127 128 129def quoted_for_c_string(s): 130 for old, new in ( 131 ('\\', '\\\\'), # must be first! 132 ('"', '\\"'), 133 ("'", "\\'"), 134 ): 135 s = s.replace(old, new) 136 return s 137 138def c_repr(s): 139 return '"' + s + '"' 140 141 142is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match 143 144def is_legal_py_identifier(s): 145 return all(is_legal_c_identifier(field) for field in s.split('.')) 146 147# identifiers that are okay in Python but aren't a good idea in C. 148# so if they're used Argument Clinic will add "_value" to the end 149# of the name in C. 150c_keywords = set(""" 151asm auto break case char const continue default do double 152else enum extern float for goto if inline int long 153register return short signed sizeof static struct switch 154typedef typeof union unsigned void volatile while 155""".strip().split()) 156 157def ensure_legal_c_identifier(s): 158 # for now, just complain if what we're given isn't legal 159 if not is_legal_c_identifier(s): 160 fail("Illegal C identifier: {}".format(s)) 161 # but if we picked a C keyword, pick something else 162 if s in c_keywords: 163 return s + "_value" 164 return s 165 166def rstrip_lines(s): 167 text, add, output = _text_accumulator() 168 for line in s.split('\n'): 169 add(line.rstrip()) 170 add('\n') 171 text.pop() 172 return output() 173 174def format_escape(s): 175 # double up curly-braces, this string will be used 176 # as part of a format_map() template later 177 s = s.replace('{', '{{') 178 s = s.replace('}', '}}') 179 return s 180 181def linear_format(s, **kwargs): 182 """ 183 Perform str.format-like substitution, except: 184 * The strings substituted must be on lines by 185 themselves. (This line is the "source line".) 186 * If the substitution text is empty, the source line 187 is removed in the output. 188 * If the field is not recognized, the original line 189 is passed unmodified through to the output. 190 * If the substitution text is not empty: 191 * Each line of the substituted text is indented 192 by the indent of the source line. 193 * A newline will be added to the end. 194 """ 195 196 add, output = text_accumulator() 197 for line in s.split('\n'): 198 indent, curly, trailing = line.partition('{') 199 if not curly: 200 add(line) 201 add('\n') 202 continue 203 204 name, curly, trailing = trailing.partition('}') 205 if not curly or name not in kwargs: 206 add(line) 207 add('\n') 208 continue 209 210 if trailing: 211 fail("Text found after {" + name + "} block marker! It must be on a line by itself.") 212 if indent.strip(): 213 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.") 214 215 value = kwargs[name] 216 if not value: 217 continue 218 219 value = textwrap.indent(rstrip_lines(value), indent) 220 add(value) 221 add('\n') 222 223 return output()[:-1] 224 225def indent_all_lines(s, prefix): 226 """ 227 Returns 's', with 'prefix' prepended to all lines. 228 229 If the last line is empty, prefix is not prepended 230 to it. (If s is blank, returns s unchanged.) 231 232 (textwrap.indent only adds to non-blank lines.) 233 """ 234 split = s.split('\n') 235 last = split.pop() 236 final = [] 237 for line in split: 238 final.append(prefix) 239 final.append(line) 240 final.append('\n') 241 if last: 242 final.append(prefix) 243 final.append(last) 244 return ''.join(final) 245 246def suffix_all_lines(s, suffix): 247 """ 248 Returns 's', with 'suffix' appended to all lines. 249 250 If the last line is empty, suffix is not appended 251 to it. (If s is blank, returns s unchanged.) 252 """ 253 split = s.split('\n') 254 last = split.pop() 255 final = [] 256 for line in split: 257 final.append(line) 258 final.append(suffix) 259 final.append('\n') 260 if last: 261 final.append(last) 262 final.append(suffix) 263 return ''.join(final) 264 265 266def version_splitter(s): 267 """Splits a version string into a tuple of integers. 268 269 The following ASCII characters are allowed, and employ 270 the following conversions: 271 a -> -3 272 b -> -2 273 c -> -1 274 (This permits Python-style version strings such as "1.4b3".) 275 """ 276 version = [] 277 accumulator = [] 278 def flush(): 279 if not accumulator: 280 raise ValueError('Unsupported version string: ' + repr(s)) 281 version.append(int(''.join(accumulator))) 282 accumulator.clear() 283 284 for c in s: 285 if c.isdigit(): 286 accumulator.append(c) 287 elif c == '.': 288 flush() 289 elif c in 'abc': 290 flush() 291 version.append('abc'.index(c) - 3) 292 else: 293 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s)) 294 flush() 295 return tuple(version) 296 297def version_comparitor(version1, version2): 298 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0) 299 for i, (a, b) in enumerate(iterator): 300 if a < b: 301 return -1 302 if a > b: 303 return 1 304 return 0 305 306 307class CRenderData: 308 def __init__(self): 309 310 # The C statements to declare variables. 311 # Should be full lines with \n eol characters. 312 self.declarations = [] 313 314 # The C statements required to initialize the variables before the parse call. 315 # Should be full lines with \n eol characters. 316 self.initializers = [] 317 318 # The C statements needed to dynamically modify the values 319 # parsed by the parse call, before calling the impl. 320 self.modifications = [] 321 322 # The entries for the "keywords" array for PyArg_ParseTuple. 323 # Should be individual strings representing the names. 324 self.keywords = [] 325 326 # The "format units" for PyArg_ParseTuple. 327 # Should be individual strings that will get 328 self.format_units = [] 329 330 # The varargs arguments for PyArg_ParseTuple. 331 self.parse_arguments = [] 332 333 # The parameter declarations for the impl function. 334 self.impl_parameters = [] 335 336 # The arguments to the impl function at the time it's called. 337 self.impl_arguments = [] 338 339 # For return converters: the name of the variable that 340 # should receive the value returned by the impl. 341 self.return_value = "return_value" 342 343 # For return converters: the code to convert the return 344 # value from the parse function. This is also where 345 # you should check the _return_value for errors, and 346 # "goto exit" if there are any. 347 self.return_conversion = [] 348 349 # The C statements required to clean up after the impl call. 350 self.cleanup = [] 351 352 353class FormatCounterFormatter(string.Formatter): 354 """ 355 This counts how many instances of each formatter 356 "replacement string" appear in the format string. 357 358 e.g. after evaluating "string {a}, {b}, {c}, {a}" 359 the counts dict would now look like 360 {'a': 2, 'b': 1, 'c': 1} 361 """ 362 def __init__(self): 363 self.counts = collections.Counter() 364 365 def get_value(self, key, args, kwargs): 366 self.counts[key] += 1 367 return '' 368 369class Language(metaclass=abc.ABCMeta): 370 371 start_line = "" 372 body_prefix = "" 373 stop_line = "" 374 checksum_line = "" 375 376 def __init__(self, filename): 377 pass 378 379 @abc.abstractmethod 380 def render(self, clinic, signatures): 381 pass 382 383 def parse_line(self, line): 384 pass 385 386 def validate(self): 387 def assert_only_one(attr, *additional_fields): 388 """ 389 Ensures that the string found at getattr(self, attr) 390 contains exactly one formatter replacement string for 391 each valid field. The list of valid fields is 392 ['dsl_name'] extended by additional_fields. 393 394 e.g. 395 self.fmt = "{dsl_name} {a} {b}" 396 397 # this passes 398 self.assert_only_one('fmt', 'a', 'b') 399 400 # this fails, the format string has a {b} in it 401 self.assert_only_one('fmt', 'a') 402 403 # this fails, the format string doesn't have a {c} in it 404 self.assert_only_one('fmt', 'a', 'b', 'c') 405 406 # this fails, the format string has two {a}s in it, 407 # it must contain exactly one 408 self.fmt2 = '{dsl_name} {a} {a}' 409 self.assert_only_one('fmt2', 'a') 410 411 """ 412 fields = ['dsl_name'] 413 fields.extend(additional_fields) 414 line = getattr(self, attr) 415 fcf = FormatCounterFormatter() 416 fcf.format(line) 417 def local_fail(should_be_there_but_isnt): 418 if should_be_there_but_isnt: 419 fail("{} {} must contain {{{}}} exactly once!".format( 420 self.__class__.__name__, attr, name)) 421 else: 422 fail("{} {} must not contain {{{}}}!".format( 423 self.__class__.__name__, attr, name)) 424 425 for name, count in fcf.counts.items(): 426 if name in fields: 427 if count > 1: 428 local_fail(True) 429 else: 430 local_fail(False) 431 for name in fields: 432 if fcf.counts.get(name) != 1: 433 local_fail(True) 434 435 assert_only_one('start_line') 436 assert_only_one('stop_line') 437 438 field = "arguments" if "{arguments}" in self.checksum_line else "checksum" 439 assert_only_one('checksum_line', field) 440 441 442 443class PythonLanguage(Language): 444 445 language = 'Python' 446 start_line = "#/*[{dsl_name} input]" 447 body_prefix = "#" 448 stop_line = "#[{dsl_name} start generated code]*/" 449 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/" 450 451 452def permute_left_option_groups(l): 453 """ 454 Given [1, 2, 3], should yield: 455 () 456 (3,) 457 (2, 3) 458 (1, 2, 3) 459 """ 460 yield tuple() 461 accumulator = [] 462 for group in reversed(l): 463 accumulator = list(group) + accumulator 464 yield tuple(accumulator) 465 466 467def permute_right_option_groups(l): 468 """ 469 Given [1, 2, 3], should yield: 470 () 471 (1,) 472 (1, 2) 473 (1, 2, 3) 474 """ 475 yield tuple() 476 accumulator = [] 477 for group in l: 478 accumulator.extend(group) 479 yield tuple(accumulator) 480 481 482def permute_optional_groups(left, required, right): 483 """ 484 Generator function that computes the set of acceptable 485 argument lists for the provided iterables of 486 argument groups. (Actually it generates a tuple of tuples.) 487 488 Algorithm: prefer left options over right options. 489 490 If required is empty, left must also be empty. 491 """ 492 required = tuple(required) 493 result = [] 494 495 if not required: 496 assert not left 497 498 accumulator = [] 499 counts = set() 500 for r in permute_right_option_groups(right): 501 for l in permute_left_option_groups(left): 502 t = l + required + r 503 if len(t) in counts: 504 continue 505 counts.add(len(t)) 506 accumulator.append(t) 507 508 accumulator.sort(key=len) 509 return tuple(accumulator) 510 511 512def strip_leading_and_trailing_blank_lines(s): 513 lines = s.rstrip().split('\n') 514 while lines: 515 line = lines[0] 516 if line.strip(): 517 break 518 del lines[0] 519 return '\n'.join(lines) 520 521@functools.lru_cache() 522def normalize_snippet(s, *, indent=0): 523 """ 524 Reformats s: 525 * removes leading and trailing blank lines 526 * ensures that it does not end with a newline 527 * dedents so the first nonwhite character on any line is at column "indent" 528 """ 529 s = strip_leading_and_trailing_blank_lines(s) 530 s = textwrap.dedent(s) 531 if indent: 532 s = textwrap.indent(s, ' ' * indent) 533 return s 534 535 536def wrap_declarations(text, length=78): 537 """ 538 A simple-minded text wrapper for C function declarations. 539 540 It views a declaration line as looking like this: 541 xxxxxxxx(xxxxxxxxx,xxxxxxxxx) 542 If called with length=30, it would wrap that line into 543 xxxxxxxx(xxxxxxxxx, 544 xxxxxxxxx) 545 (If the declaration has zero or one parameters, this 546 function won't wrap it.) 547 548 If this doesn't work properly, it's probably better to 549 start from scratch with a more sophisticated algorithm, 550 rather than try and improve/debug this dumb little function. 551 """ 552 lines = [] 553 for line in text.split('\n'): 554 prefix, _, after_l_paren = line.partition('(') 555 if not after_l_paren: 556 lines.append(line) 557 continue 558 parameters, _, after_r_paren = after_l_paren.partition(')') 559 if not _: 560 lines.append(line) 561 continue 562 if ',' not in parameters: 563 lines.append(line) 564 continue 565 parameters = [x.strip() + ", " for x in parameters.split(',')] 566 prefix += "(" 567 if len(prefix) < length: 568 spaces = " " * len(prefix) 569 else: 570 spaces = " " * 4 571 572 while parameters: 573 line = prefix 574 first = True 575 while parameters: 576 if (not first and 577 (len(line) + len(parameters[0]) > length)): 578 break 579 line += parameters.pop(0) 580 first = False 581 if not parameters: 582 line = line.rstrip(", ") + ")" + after_r_paren 583 lines.append(line.rstrip()) 584 prefix = spaces 585 return "\n".join(lines) 586 587 588class CLanguage(Language): 589 590 body_prefix = "#" 591 language = 'C' 592 start_line = "/*[{dsl_name} input]" 593 body_prefix = "" 594 stop_line = "[{dsl_name} start generated code]*/" 595 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/" 596 597 def __init__(self, filename): 598 super().__init__(filename) 599 self.cpp = cpp.Monitor(filename) 600 self.cpp.fail = fail 601 602 def parse_line(self, line): 603 self.cpp.writeline(line) 604 605 def render(self, clinic, signatures): 606 function = None 607 for o in signatures: 608 if isinstance(o, Function): 609 if function: 610 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o)) 611 function = o 612 return self.render_function(clinic, function) 613 614 def docstring_for_c_string(self, f): 615 if re.search(r'[^\x00-\x7F]', f.docstring): 616 warn("Non-ascii character appear in docstring.") 617 618 text, add, output = _text_accumulator() 619 # turn docstring into a properly quoted C string 620 for line in f.docstring.split('\n'): 621 add('"') 622 add(quoted_for_c_string(line)) 623 add('\\n"\n') 624 625 if text[-2] == sig_end_marker: 626 # If we only have a signature, add the blank line that the 627 # __text_signature__ getter expects to be there. 628 add('"\\n"') 629 else: 630 text.pop() 631 add('"') 632 return ''.join(text) 633 634 def output_templates(self, f): 635 parameters = list(f.parameters.values()) 636 assert parameters 637 assert isinstance(parameters[0].converter, self_converter) 638 del parameters[0] 639 converters = [p.converter for p in parameters] 640 641 has_option_groups = parameters and (parameters[0].group or parameters[-1].group) 642 default_return_converter = (not f.return_converter or 643 f.return_converter.type == 'PyObject *') 644 645 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 646 647 pos_only = min_pos = max_pos = min_kw_only = 0 648 for i, p in enumerate(parameters, 1): 649 if p.is_keyword_only(): 650 assert not p.is_positional_only() 651 if not p.is_optional(): 652 min_kw_only = i - max_pos 653 else: 654 max_pos = i 655 if p.is_positional_only(): 656 pos_only = i 657 if not p.is_optional(): 658 min_pos = i 659 660 requires_defining_class = any( 661 isinstance(p.converter, defining_class_converter) 662 for p in parameters) 663 664 meth_o = (len(parameters) == 1 and 665 parameters[0].is_positional_only() and 666 not converters[0].is_optional() and 667 not requires_defining_class and 668 not new_or_init) 669 670 # we have to set these things before we're done: 671 # 672 # docstring_prototype 673 # docstring_definition 674 # impl_prototype 675 # methoddef_define 676 # parser_prototype 677 # parser_definition 678 # impl_definition 679 # cpp_if 680 # cpp_endif 681 # methoddef_ifndef 682 683 return_value_declaration = "PyObject *return_value = NULL;" 684 685 methoddef_define = normalize_snippet(""" 686 #define {methoddef_name} \\ 687 {{"{name}", {methoddef_cast}{c_basename}, {methoddef_flags}, {c_basename}__doc__}}, 688 """) 689 if new_or_init and not f.docstring: 690 docstring_prototype = docstring_definition = '' 691 else: 692 docstring_prototype = normalize_snippet(""" 693 PyDoc_VAR({c_basename}__doc__); 694 """) 695 docstring_definition = normalize_snippet(""" 696 PyDoc_STRVAR({c_basename}__doc__, 697 {docstring}); 698 """) 699 impl_definition = normalize_snippet(""" 700 static {impl_return_type} 701 {c_basename}_impl({impl_parameters}) 702 """) 703 impl_prototype = parser_prototype = parser_definition = None 704 705 parser_prototype_keyword = normalize_snippet(""" 706 static PyObject * 707 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) 708 """) 709 710 parser_prototype_varargs = normalize_snippet(""" 711 static PyObject * 712 {c_basename}({self_type}{self_name}, PyObject *args) 713 """) 714 715 parser_prototype_fastcall = normalize_snippet(""" 716 static PyObject * 717 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs) 718 """) 719 720 parser_prototype_fastcall_keywords = normalize_snippet(""" 721 static PyObject * 722 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) 723 """) 724 725 parser_prototype_def_class = normalize_snippet(""" 726 static PyObject * 727 {c_basename}({self_type}{self_name}, PyTypeObject *{defining_class_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) 728 """) 729 730 # parser_body_fields remembers the fields passed in to the 731 # previous call to parser_body. this is used for an awful hack. 732 parser_body_fields = () 733 parser_body_declarations = '' 734 def parser_body(prototype, *fields, declarations=''): 735 nonlocal parser_body_fields, parser_body_declarations 736 add, output = text_accumulator() 737 add(prototype) 738 parser_body_fields = fields 739 parser_body_declarations = declarations 740 741 fields = list(fields) 742 fields.insert(0, normalize_snippet(""" 743 {{ 744 {return_value_declaration} 745 {parser_declarations} 746 {declarations} 747 {initializers} 748 """) + "\n") 749 # just imagine--your code is here in the middle 750 fields.append(normalize_snippet(""" 751 {modifications} 752 {return_value} = {c_basename}_impl({impl_arguments}); 753 {return_conversion} 754 755 {exit_label} 756 {cleanup} 757 return return_value; 758 }} 759 """)) 760 for field in fields: 761 add('\n') 762 add(field) 763 return linear_format(output(), parser_declarations=declarations) 764 765 if not parameters: 766 # no parameters, METH_NOARGS 767 768 flags = "METH_NOARGS" 769 770 parser_prototype = normalize_snippet(""" 771 static PyObject * 772 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) 773 """) 774 parser_definition = parser_prototype 775 776 if default_return_converter: 777 parser_definition = parser_prototype + '\n' + normalize_snippet(""" 778 {{ 779 return {c_basename}_impl({impl_arguments}); 780 }} 781 """) 782 else: 783 parser_definition = parser_body(parser_prototype) 784 785 elif meth_o: 786 flags = "METH_O" 787 788 if (isinstance(converters[0], object_converter) and 789 converters[0].format_unit == 'O'): 790 meth_o_prototype = normalize_snippet(""" 791 static PyObject * 792 {c_basename}({impl_parameters}) 793 """) 794 795 if default_return_converter: 796 # maps perfectly to METH_O, doesn't need a return converter. 797 # so we skip making a parse function 798 # and call directly into the impl function. 799 impl_prototype = parser_prototype = parser_definition = '' 800 impl_definition = meth_o_prototype 801 else: 802 # SLIGHT HACK 803 # use impl_parameters for the parser here! 804 parser_prototype = meth_o_prototype 805 parser_definition = parser_body(parser_prototype) 806 807 else: 808 argname = 'arg' 809 if parameters[0].name == argname: 810 argname += '_' 811 parser_prototype = normalize_snippet(""" 812 static PyObject * 813 {c_basename}({self_type}{self_name}, PyObject *%s) 814 """ % argname) 815 816 displayname = parameters[0].get_displayname(0) 817 parsearg = converters[0].parse_arg(argname, displayname) 818 if parsearg is None: 819 parsearg = """ 820 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{ 821 goto exit; 822 }} 823 """ % argname 824 parser_definition = parser_body(parser_prototype, 825 normalize_snippet(parsearg, indent=4)) 826 827 elif has_option_groups: 828 # positional parameters with option groups 829 # (we have to generate lots of PyArg_ParseTuple calls 830 # in a big switch statement) 831 832 flags = "METH_VARARGS" 833 parser_prototype = parser_prototype_varargs 834 835 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}') 836 837 elif not requires_defining_class and pos_only == len(parameters): 838 if not new_or_init: 839 # positional-only, but no option groups 840 # we only need one call to _PyArg_ParseStack 841 842 flags = "METH_FASTCALL" 843 parser_prototype = parser_prototype_fastcall 844 nargs = 'nargs' 845 argname_fmt = 'args[%d]' 846 else: 847 # positional-only, but no option groups 848 # we only need one call to PyArg_ParseTuple 849 850 flags = "METH_VARARGS" 851 parser_prototype = parser_prototype_varargs 852 nargs = 'PyTuple_GET_SIZE(args)' 853 argname_fmt = 'PyTuple_GET_ITEM(args, %d)' 854 855 parser_code = [normalize_snippet(""" 856 if (!_PyArg_CheckPositional("{name}", %s, %d, %d)) {{ 857 goto exit; 858 }} 859 """ % (nargs, min_pos, max_pos), indent=4)] 860 has_optional = False 861 for i, p in enumerate(parameters): 862 displayname = p.get_displayname(i+1) 863 parsearg = p.converter.parse_arg(argname_fmt % i, displayname) 864 if parsearg is None: 865 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr) 866 parser_code = None 867 break 868 if has_optional or p.is_optional(): 869 has_optional = True 870 parser_code.append(normalize_snippet(""" 871 if (%s < %d) {{ 872 goto skip_optional; 873 }} 874 """, indent=4) % (nargs, i + 1)) 875 parser_code.append(normalize_snippet(parsearg, indent=4)) 876 877 if parser_code is not None: 878 if has_optional: 879 parser_code.append("skip_optional:") 880 else: 881 if not new_or_init: 882 parser_code = [normalize_snippet(""" 883 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}", 884 {parse_arguments})) {{ 885 goto exit; 886 }} 887 """, indent=4)] 888 else: 889 parser_code = [normalize_snippet(""" 890 if (!PyArg_ParseTuple(args, "{format_units}:{name}", 891 {parse_arguments})) {{ 892 goto exit; 893 }} 894 """, indent=4)] 895 parser_definition = parser_body(parser_prototype, *parser_code) 896 897 else: 898 has_optional_kw = (max(pos_only, min_pos) + min_kw_only < len(converters)) 899 if not new_or_init: 900 flags = "METH_FASTCALL|METH_KEYWORDS" 901 parser_prototype = parser_prototype_fastcall_keywords 902 argname_fmt = 'args[%d]' 903 declarations = normalize_snippet(""" 904 static const char * const _keywords[] = {{{keywords} NULL}}; 905 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}}; 906 PyObject *argsbuf[%s]; 907 """ % len(converters)) 908 if has_optional_kw: 909 declarations += "\nPy_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (min_pos + min_kw_only) 910 parser_code = [normalize_snippet(""" 911 args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, %d, %d, %d, argsbuf); 912 if (!args) {{ 913 goto exit; 914 }} 915 """ % (min_pos, max_pos, min_kw_only), indent=4)] 916 else: 917 # positional-or-keyword arguments 918 flags = "METH_VARARGS|METH_KEYWORDS" 919 parser_prototype = parser_prototype_keyword 920 argname_fmt = 'fastargs[%d]' 921 declarations = normalize_snippet(""" 922 static const char * const _keywords[] = {{{keywords} NULL}}; 923 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}}; 924 PyObject *argsbuf[%s]; 925 PyObject * const *fastargs; 926 Py_ssize_t nargs = PyTuple_GET_SIZE(args); 927 """ % len(converters)) 928 if has_optional_kw: 929 declarations += "\nPy_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (min_pos + min_kw_only) 930 parser_code = [normalize_snippet(""" 931 fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %d, %d, %d, argsbuf); 932 if (!fastargs) {{ 933 goto exit; 934 }} 935 """ % (min_pos, max_pos, min_kw_only), indent=4)] 936 if requires_defining_class: 937 flags = 'METH_METHOD|' + flags 938 parser_prototype = parser_prototype_def_class 939 940 add_label = None 941 for i, p in enumerate(parameters): 942 displayname = p.get_displayname(i+1) 943 parsearg = p.converter.parse_arg(argname_fmt % i, displayname) 944 if parsearg is None: 945 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr) 946 parser_code = None 947 break 948 if add_label and (i == pos_only or i == max_pos): 949 parser_code.append("%s:" % add_label) 950 add_label = None 951 if not p.is_optional(): 952 parser_code.append(normalize_snippet(parsearg, indent=4)) 953 elif i < pos_only: 954 add_label = 'skip_optional_posonly' 955 parser_code.append(normalize_snippet(""" 956 if (nargs < %d) {{ 957 goto %s; 958 }} 959 """ % (i + 1, add_label), indent=4)) 960 if has_optional_kw: 961 parser_code.append(normalize_snippet(""" 962 noptargs--; 963 """, indent=4)) 964 parser_code.append(normalize_snippet(parsearg, indent=4)) 965 else: 966 if i < max_pos: 967 label = 'skip_optional_pos' 968 first_opt = max(min_pos, pos_only) 969 else: 970 label = 'skip_optional_kwonly' 971 first_opt = max_pos + min_kw_only 972 if i == first_opt: 973 add_label = label 974 parser_code.append(normalize_snippet(""" 975 if (!noptargs) {{ 976 goto %s; 977 }} 978 """ % add_label, indent=4)) 979 if i + 1 == len(parameters): 980 parser_code.append(normalize_snippet(parsearg, indent=4)) 981 else: 982 add_label = label 983 parser_code.append(normalize_snippet(""" 984 if (%s) {{ 985 """ % (argname_fmt % i), indent=4)) 986 parser_code.append(normalize_snippet(parsearg, indent=8)) 987 parser_code.append(normalize_snippet(""" 988 if (!--noptargs) {{ 989 goto %s; 990 }} 991 }} 992 """ % add_label, indent=4)) 993 994 if parser_code is not None: 995 if add_label: 996 parser_code.append("%s:" % add_label) 997 else: 998 declarations = ( 999 'static const char * const _keywords[] = {{{keywords} NULL}};\n' 1000 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};') 1001 if not new_or_init: 1002 parser_code = [normalize_snippet(""" 1003 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser{parse_arguments_comma} 1004 {parse_arguments})) {{ 1005 goto exit; 1006 }} 1007 """, indent=4)] 1008 else: 1009 parser_code = [normalize_snippet(""" 1010 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, 1011 {parse_arguments})) {{ 1012 goto exit; 1013 }} 1014 """, indent=4)] 1015 parser_definition = parser_body(parser_prototype, *parser_code, 1016 declarations=declarations) 1017 1018 1019 if new_or_init: 1020 methoddef_define = '' 1021 1022 if f.kind == METHOD_NEW: 1023 parser_prototype = parser_prototype_keyword 1024 else: 1025 return_value_declaration = "int return_value = -1;" 1026 parser_prototype = normalize_snippet(""" 1027 static int 1028 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) 1029 """) 1030 1031 fields = list(parser_body_fields) 1032 parses_positional = 'METH_NOARGS' not in flags 1033 parses_keywords = 'METH_KEYWORDS' in flags 1034 if parses_keywords: 1035 assert parses_positional 1036 1037 if requires_defining_class: 1038 raise ValueError("Slot methods cannot access their defining class.") 1039 1040 if not parses_keywords: 1041 fields.insert(0, normalize_snippet(""" 1042 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{ 1043 goto exit; 1044 }} 1045 """, indent=4)) 1046 if not parses_positional: 1047 fields.insert(0, normalize_snippet(""" 1048 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{ 1049 goto exit; 1050 }} 1051 """, indent=4)) 1052 1053 parser_definition = parser_body(parser_prototype, *fields, 1054 declarations=parser_body_declarations) 1055 1056 1057 if flags in ('METH_NOARGS', 'METH_O', 'METH_VARARGS'): 1058 methoddef_cast = "(PyCFunction)" 1059 else: 1060 methoddef_cast = "(PyCFunction)(void(*)(void))" 1061 1062 if f.methoddef_flags: 1063 flags += '|' + f.methoddef_flags 1064 1065 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags) 1066 methoddef_define = methoddef_define.replace('{methoddef_cast}', methoddef_cast) 1067 1068 methoddef_ifndef = '' 1069 conditional = self.cpp.condition() 1070 if not conditional: 1071 cpp_if = cpp_endif = '' 1072 else: 1073 cpp_if = "#if " + conditional 1074 cpp_endif = "#endif /* " + conditional + " */" 1075 1076 if methoddef_define and f.full_name not in clinic.ifndef_symbols: 1077 clinic.ifndef_symbols.add(f.full_name) 1078 methoddef_ifndef = normalize_snippet(""" 1079 #ifndef {methoddef_name} 1080 #define {methoddef_name} 1081 #endif /* !defined({methoddef_name}) */ 1082 """) 1083 1084 1085 # add ';' to the end of parser_prototype and impl_prototype 1086 # (they mustn't be None, but they could be an empty string.) 1087 assert parser_prototype is not None 1088 if parser_prototype: 1089 assert not parser_prototype.endswith(';') 1090 parser_prototype += ';' 1091 1092 if impl_prototype is None: 1093 impl_prototype = impl_definition 1094 if impl_prototype: 1095 impl_prototype += ";" 1096 1097 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration) 1098 1099 d = { 1100 "docstring_prototype" : docstring_prototype, 1101 "docstring_definition" : docstring_definition, 1102 "impl_prototype" : impl_prototype, 1103 "methoddef_define" : methoddef_define, 1104 "parser_prototype" : parser_prototype, 1105 "parser_definition" : parser_definition, 1106 "impl_definition" : impl_definition, 1107 "cpp_if" : cpp_if, 1108 "cpp_endif" : cpp_endif, 1109 "methoddef_ifndef" : methoddef_ifndef, 1110 } 1111 1112 # make sure we didn't forget to assign something, 1113 # and wrap each non-empty value in \n's 1114 d2 = {} 1115 for name, value in d.items(): 1116 assert value is not None, "got a None value for template " + repr(name) 1117 if value: 1118 value = '\n' + value + '\n' 1119 d2[name] = value 1120 return d2 1121 1122 @staticmethod 1123 def group_to_variable_name(group): 1124 adjective = "left_" if group < 0 else "right_" 1125 return "group_" + adjective + str(abs(group)) 1126 1127 def render_option_group_parsing(self, f, template_dict): 1128 # positional only, grouped, optional arguments! 1129 # can be optional on the left or right. 1130 # here's an example: 1131 # 1132 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ] 1133 # 1134 # Here group D are required, and all other groups are optional. 1135 # (Group D's "group" is actually None.) 1136 # We can figure out which sets of arguments we have based on 1137 # how many arguments are in the tuple. 1138 # 1139 # Note that you need to count up on both sides. For example, 1140 # you could have groups C+D, or C+D+E, or C+D+E+F. 1141 # 1142 # What if the number of arguments leads us to an ambiguous result? 1143 # Clinic prefers groups on the left. So in the above example, 1144 # five arguments would map to B+C, not C+D. 1145 1146 add, output = text_accumulator() 1147 parameters = list(f.parameters.values()) 1148 if isinstance(parameters[0].converter, self_converter): 1149 del parameters[0] 1150 1151 groups = [] 1152 group = None 1153 left = [] 1154 right = [] 1155 required = [] 1156 last = unspecified 1157 1158 for p in parameters: 1159 group_id = p.group 1160 if group_id != last: 1161 last = group_id 1162 group = [] 1163 if group_id < 0: 1164 left.append(group) 1165 elif group_id == 0: 1166 group = required 1167 else: 1168 right.append(group) 1169 group.append(p) 1170 1171 count_min = sys.maxsize 1172 count_max = -1 1173 1174 add("switch (PyTuple_GET_SIZE(args)) {\n") 1175 for subset in permute_optional_groups(left, required, right): 1176 count = len(subset) 1177 count_min = min(count_min, count) 1178 count_max = max(count_max, count) 1179 1180 if count == 0: 1181 add(""" case 0: 1182 break; 1183""") 1184 continue 1185 1186 group_ids = {p.group for p in subset} # eliminate duplicates 1187 d = {} 1188 d['count'] = count 1189 d['name'] = f.name 1190 d['format_units'] = "".join(p.converter.format_unit for p in subset) 1191 1192 parse_arguments = [] 1193 for p in subset: 1194 p.converter.parse_argument(parse_arguments) 1195 d['parse_arguments'] = ", ".join(parse_arguments) 1196 1197 group_ids.discard(0) 1198 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids] 1199 lines = "\n".join(lines) 1200 1201 s = """\ 1202 case {count}: 1203 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{ 1204 goto exit; 1205 }} 1206 {group_booleans} 1207 break; 1208""" 1209 s = linear_format(s, group_booleans=lines) 1210 s = s.format_map(d) 1211 add(s) 1212 1213 add(" default:\n") 1214 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n' 1215 add(s.format(f.full_name, count_min, count_max)) 1216 add(' goto exit;\n') 1217 add("}") 1218 template_dict['option_group_parsing'] = format_escape(output()) 1219 1220 def render_function(self, clinic, f): 1221 if not f: 1222 return "" 1223 1224 add, output = text_accumulator() 1225 data = CRenderData() 1226 1227 assert f.parameters, "We should always have a 'self' at this point!" 1228 parameters = f.render_parameters 1229 converters = [p.converter for p in parameters] 1230 1231 templates = self.output_templates(f) 1232 1233 f_self = parameters[0] 1234 selfless = parameters[1:] 1235 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!" 1236 1237 last_group = 0 1238 first_optional = len(selfless) 1239 positional = selfless and selfless[-1].is_positional_only() 1240 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 1241 default_return_converter = (not f.return_converter or 1242 f.return_converter.type == 'PyObject *') 1243 has_option_groups = False 1244 1245 # offset i by -1 because first_optional needs to ignore self 1246 for i, p in enumerate(parameters, -1): 1247 c = p.converter 1248 1249 if (i != -1) and (p.default is not unspecified): 1250 first_optional = min(first_optional, i) 1251 1252 # insert group variable 1253 group = p.group 1254 if last_group != group: 1255 last_group = group 1256 if group: 1257 group_name = self.group_to_variable_name(group) 1258 data.impl_arguments.append(group_name) 1259 data.declarations.append("int " + group_name + " = 0;") 1260 data.impl_parameters.append("int " + group_name) 1261 has_option_groups = True 1262 1263 c.render(p, data) 1264 1265 if has_option_groups and (not positional): 1266 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').") 1267 1268 # HACK 1269 # when we're METH_O, but have a custom return converter, 1270 # we use "impl_parameters" for the parsing function 1271 # because that works better. but that means we must 1272 # suppress actually declaring the impl's parameters 1273 # as variables in the parsing function. but since it's 1274 # METH_O, we have exactly one anyway, so we know exactly 1275 # where it is. 1276 if ("METH_O" in templates['methoddef_define'] and 1277 '{impl_parameters}' in templates['parser_prototype']): 1278 data.declarations.pop(0) 1279 1280 template_dict = {} 1281 1282 full_name = f.full_name 1283 template_dict['full_name'] = full_name 1284 1285 if new_or_init: 1286 name = f.cls.name 1287 else: 1288 name = f.name 1289 1290 template_dict['name'] = name 1291 1292 if f.c_basename: 1293 c_basename = f.c_basename 1294 else: 1295 fields = full_name.split(".") 1296 if fields[-1] == '__new__': 1297 fields.pop() 1298 c_basename = "_".join(fields) 1299 1300 template_dict['c_basename'] = c_basename 1301 1302 methoddef_name = "{}_METHODDEF".format(c_basename.upper()) 1303 template_dict['methoddef_name'] = methoddef_name 1304 1305 template_dict['docstring'] = self.docstring_for_c_string(f) 1306 1307 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = '' 1308 for converter in converters: 1309 converter.set_template_dict(template_dict) 1310 1311 f.return_converter.render(f, data) 1312 template_dict['impl_return_type'] = f.return_converter.type 1313 1314 template_dict['declarations'] = format_escape("\n".join(data.declarations)) 1315 template_dict['initializers'] = "\n\n".join(data.initializers) 1316 template_dict['modifications'] = '\n\n'.join(data.modifications) 1317 template_dict['keywords'] = ' '.join('"' + k + '",' for k in data.keywords) 1318 template_dict['format_units'] = ''.join(data.format_units) 1319 template_dict['parse_arguments'] = ', '.join(data.parse_arguments) 1320 if data.parse_arguments: 1321 template_dict['parse_arguments_comma'] = ','; 1322 else: 1323 template_dict['parse_arguments_comma'] = ''; 1324 template_dict['impl_parameters'] = ", ".join(data.impl_parameters) 1325 template_dict['impl_arguments'] = ", ".join(data.impl_arguments) 1326 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip()) 1327 template_dict['cleanup'] = format_escape("".join(data.cleanup)) 1328 template_dict['return_value'] = data.return_value 1329 1330 # used by unpack tuple code generator 1331 ignore_self = -1 if isinstance(converters[0], self_converter) else 0 1332 unpack_min = first_optional 1333 unpack_max = len(selfless) 1334 template_dict['unpack_min'] = str(unpack_min) 1335 template_dict['unpack_max'] = str(unpack_max) 1336 1337 if has_option_groups: 1338 self.render_option_group_parsing(f, template_dict) 1339 1340 # buffers, not destination 1341 for name, destination in clinic.destination_buffers.items(): 1342 template = templates[name] 1343 if has_option_groups: 1344 template = linear_format(template, 1345 option_group_parsing=template_dict['option_group_parsing']) 1346 template = linear_format(template, 1347 declarations=template_dict['declarations'], 1348 return_conversion=template_dict['return_conversion'], 1349 initializers=template_dict['initializers'], 1350 modifications=template_dict['modifications'], 1351 cleanup=template_dict['cleanup'], 1352 ) 1353 1354 # Only generate the "exit:" label 1355 # if we have any gotos 1356 need_exit_label = "goto exit;" in template 1357 template = linear_format(template, 1358 exit_label="exit:" if need_exit_label else '' 1359 ) 1360 1361 s = template.format_map(template_dict) 1362 1363 # mild hack: 1364 # reflow long impl declarations 1365 if name in {"impl_prototype", "impl_definition"}: 1366 s = wrap_declarations(s) 1367 1368 if clinic.line_prefix: 1369 s = indent_all_lines(s, clinic.line_prefix) 1370 if clinic.line_suffix: 1371 s = suffix_all_lines(s, clinic.line_suffix) 1372 1373 destination.append(s) 1374 1375 return clinic.get_destination('block').dump() 1376 1377 1378 1379 1380@contextlib.contextmanager 1381def OverrideStdioWith(stdout): 1382 saved_stdout = sys.stdout 1383 sys.stdout = stdout 1384 try: 1385 yield 1386 finally: 1387 assert sys.stdout is stdout 1388 sys.stdout = saved_stdout 1389 1390 1391def create_regex(before, after, word=True, whole_line=True): 1392 """Create an re object for matching marker lines.""" 1393 group_re = r"\w+" if word else ".+" 1394 pattern = r'{}({}){}' 1395 if whole_line: 1396 pattern = '^' + pattern + '$' 1397 pattern = pattern.format(re.escape(before), group_re, re.escape(after)) 1398 return re.compile(pattern) 1399 1400 1401class Block: 1402 r""" 1403 Represents a single block of text embedded in 1404 another file. If dsl_name is None, the block represents 1405 verbatim text, raw original text from the file, in 1406 which case "input" will be the only non-false member. 1407 If dsl_name is not None, the block represents a Clinic 1408 block. 1409 1410 input is always str, with embedded \n characters. 1411 input represents the original text from the file; 1412 if it's a Clinic block, it is the original text with 1413 the body_prefix and redundant leading whitespace removed. 1414 1415 dsl_name is either str or None. If str, it's the text 1416 found on the start line of the block between the square 1417 brackets. 1418 1419 signatures is either list or None. If it's a list, 1420 it may only contain clinic.Module, clinic.Class, and 1421 clinic.Function objects. At the moment it should 1422 contain at most one of each. 1423 1424 output is either str or None. If str, it's the output 1425 from this block, with embedded '\n' characters. 1426 1427 indent is either str or None. It's the leading whitespace 1428 that was found on every line of input. (If body_prefix is 1429 not empty, this is the indent *after* removing the 1430 body_prefix.) 1431 1432 preindent is either str or None. It's the whitespace that 1433 was found in front of every line of input *before* the 1434 "body_prefix" (see the Language object). If body_prefix 1435 is empty, preindent must always be empty too. 1436 1437 To illustrate indent and preindent: Assume that '_' 1438 represents whitespace. If the block processed was in a 1439 Python file, and looked like this: 1440 ____#/*[python] 1441 ____#__for a in range(20): 1442 ____#____print(a) 1443 ____#[python]*/ 1444 "preindent" would be "____" and "indent" would be "__". 1445 1446 """ 1447 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''): 1448 assert isinstance(input, str) 1449 self.input = input 1450 self.dsl_name = dsl_name 1451 self.signatures = signatures or [] 1452 self.output = output 1453 self.indent = indent 1454 self.preindent = preindent 1455 1456 def __repr__(self): 1457 dsl_name = self.dsl_name or "text" 1458 def summarize(s): 1459 s = repr(s) 1460 if len(s) > 30: 1461 return s[:26] + "..." + s[0] 1462 return s 1463 return "".join(( 1464 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">")) 1465 1466 1467class BlockParser: 1468 """ 1469 Block-oriented parser for Argument Clinic. 1470 Iterator, yields Block objects. 1471 """ 1472 1473 def __init__(self, input, language, *, verify=True): 1474 """ 1475 "input" should be a str object 1476 with embedded \n characters. 1477 1478 "language" should be a Language object. 1479 """ 1480 language.validate() 1481 1482 self.input = collections.deque(reversed(input.splitlines(keepends=True))) 1483 self.block_start_line_number = self.line_number = 0 1484 1485 self.language = language 1486 before, _, after = language.start_line.partition('{dsl_name}') 1487 assert _ == '{dsl_name}' 1488 self.find_start_re = create_regex(before, after, whole_line=False) 1489 self.start_re = create_regex(before, after) 1490 self.verify = verify 1491 self.last_checksum_re = None 1492 self.last_dsl_name = None 1493 self.dsl_name = None 1494 self.first_block = True 1495 1496 def __iter__(self): 1497 return self 1498 1499 def __next__(self): 1500 while True: 1501 if not self.input: 1502 raise StopIteration 1503 1504 if self.dsl_name: 1505 return_value = self.parse_clinic_block(self.dsl_name) 1506 self.dsl_name = None 1507 self.first_block = False 1508 return return_value 1509 block = self.parse_verbatim_block() 1510 if self.first_block and not block.input: 1511 continue 1512 self.first_block = False 1513 return block 1514 1515 1516 def is_start_line(self, line): 1517 match = self.start_re.match(line.lstrip()) 1518 return match.group(1) if match else None 1519 1520 def _line(self, lookahead=False): 1521 self.line_number += 1 1522 line = self.input.pop() 1523 if not lookahead: 1524 self.language.parse_line(line) 1525 return line 1526 1527 def parse_verbatim_block(self): 1528 add, output = text_accumulator() 1529 self.block_start_line_number = self.line_number 1530 1531 while self.input: 1532 line = self._line() 1533 dsl_name = self.is_start_line(line) 1534 if dsl_name: 1535 self.dsl_name = dsl_name 1536 break 1537 add(line) 1538 1539 return Block(output()) 1540 1541 def parse_clinic_block(self, dsl_name): 1542 input_add, input_output = text_accumulator() 1543 self.block_start_line_number = self.line_number + 1 1544 stop_line = self.language.stop_line.format(dsl_name=dsl_name) 1545 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name) 1546 1547 def is_stop_line(line): 1548 # make sure to recognize stop line even if it 1549 # doesn't end with EOL (it could be the very end of the file) 1550 if not line.startswith(stop_line): 1551 return False 1552 remainder = line[len(stop_line):] 1553 return (not remainder) or remainder.isspace() 1554 1555 # consume body of program 1556 while self.input: 1557 line = self._line() 1558 if is_stop_line(line) or self.is_start_line(line): 1559 break 1560 if body_prefix: 1561 line = line.lstrip() 1562 assert line.startswith(body_prefix) 1563 line = line[len(body_prefix):] 1564 input_add(line) 1565 1566 # consume output and checksum line, if present. 1567 if self.last_dsl_name == dsl_name: 1568 checksum_re = self.last_checksum_re 1569 else: 1570 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}') 1571 assert _ == '{arguments}' 1572 checksum_re = create_regex(before, after, word=False) 1573 self.last_dsl_name = dsl_name 1574 self.last_checksum_re = checksum_re 1575 1576 # scan forward for checksum line 1577 output_add, output_output = text_accumulator() 1578 arguments = None 1579 while self.input: 1580 line = self._line(lookahead=True) 1581 match = checksum_re.match(line.lstrip()) 1582 arguments = match.group(1) if match else None 1583 if arguments: 1584 break 1585 output_add(line) 1586 if self.is_start_line(line): 1587 break 1588 1589 output = output_output() 1590 if arguments: 1591 d = {} 1592 for field in shlex.split(arguments): 1593 name, equals, value = field.partition('=') 1594 if not equals: 1595 fail("Mangled Argument Clinic marker line: {!r}".format(line)) 1596 d[name.strip()] = value.strip() 1597 1598 if self.verify: 1599 if 'input' in d: 1600 checksum = d['output'] 1601 input_checksum = d['input'] 1602 else: 1603 checksum = d['checksum'] 1604 input_checksum = None 1605 1606 computed = compute_checksum(output, len(checksum)) 1607 if checksum != computed: 1608 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n" 1609 "Suggested fix: remove all generated code including " 1610 "the end marker,\n" 1611 "or use the '-f' option." 1612 .format(checksum, computed)) 1613 else: 1614 # put back output 1615 output_lines = output.splitlines(keepends=True) 1616 self.line_number -= len(output_lines) 1617 self.input.extend(reversed(output_lines)) 1618 output = None 1619 1620 return Block(input_output(), dsl_name, output=output) 1621 1622 1623class BlockPrinter: 1624 1625 def __init__(self, language, f=None): 1626 self.language = language 1627 self.f = f or io.StringIO() 1628 1629 def print_block(self, block): 1630 input = block.input 1631 output = block.output 1632 dsl_name = block.dsl_name 1633 write = self.f.write 1634 1635 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name) 1636 1637 if not dsl_name: 1638 write(input) 1639 return 1640 1641 write(self.language.start_line.format(dsl_name=dsl_name)) 1642 write("\n") 1643 1644 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name) 1645 if not body_prefix: 1646 write(input) 1647 else: 1648 for line in input.split('\n'): 1649 write(body_prefix) 1650 write(line) 1651 write("\n") 1652 1653 write(self.language.stop_line.format(dsl_name=dsl_name)) 1654 write("\n") 1655 1656 input = ''.join(block.input) 1657 output = ''.join(block.output) 1658 if output: 1659 if not output.endswith('\n'): 1660 output += '\n' 1661 write(output) 1662 1663 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16)) 1664 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments)) 1665 write("\n") 1666 1667 def write(self, text): 1668 self.f.write(text) 1669 1670 1671class BufferSeries: 1672 """ 1673 Behaves like a "defaultlist". 1674 When you ask for an index that doesn't exist yet, 1675 the object grows the list until that item exists. 1676 So o[n] will always work. 1677 1678 Supports negative indices for actual items. 1679 e.g. o[-1] is an element immediately preceding o[0]. 1680 """ 1681 1682 def __init__(self): 1683 self._start = 0 1684 self._array = [] 1685 self._constructor = _text_accumulator 1686 1687 def __getitem__(self, i): 1688 i -= self._start 1689 if i < 0: 1690 self._start += i 1691 prefix = [self._constructor() for x in range(-i)] 1692 self._array = prefix + self._array 1693 i = 0 1694 while i >= len(self._array): 1695 self._array.append(self._constructor()) 1696 return self._array[i] 1697 1698 def clear(self): 1699 for ta in self._array: 1700 ta._text.clear() 1701 1702 def dump(self): 1703 texts = [ta.output() for ta in self._array] 1704 return "".join(texts) 1705 1706 1707class Destination: 1708 def __init__(self, name, type, clinic, *args): 1709 self.name = name 1710 self.type = type 1711 self.clinic = clinic 1712 valid_types = ('buffer', 'file', 'suppress') 1713 if type not in valid_types: 1714 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types)) 1715 extra_arguments = 1 if type == "file" else 0 1716 if len(args) < extra_arguments: 1717 fail("Not enough arguments for destination " + name + " new " + type) 1718 if len(args) > extra_arguments: 1719 fail("Too many arguments for destination " + name + " new " + type) 1720 if type =='file': 1721 d = {} 1722 filename = clinic.filename 1723 d['path'] = filename 1724 dirname, basename = os.path.split(filename) 1725 if not dirname: 1726 dirname = '.' 1727 d['dirname'] = dirname 1728 d['basename'] = basename 1729 d['basename_root'], d['basename_extension'] = os.path.splitext(filename) 1730 self.filename = args[0].format_map(d) 1731 1732 self.buffers = BufferSeries() 1733 1734 def __repr__(self): 1735 if self.type == 'file': 1736 file_repr = " " + repr(self.filename) 1737 else: 1738 file_repr = '' 1739 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">")) 1740 1741 def clear(self): 1742 if self.type != 'buffer': 1743 fail("Can't clear destination" + self.name + " , it's not of type buffer") 1744 self.buffers.clear() 1745 1746 def dump(self): 1747 return self.buffers.dump() 1748 1749 1750# maps strings to Language objects. 1751# "languages" maps the name of the language ("C", "Python"). 1752# "extensions" maps the file extension ("c", "py"). 1753languages = { 'C': CLanguage, 'Python': PythonLanguage } 1754extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } 1755extensions['py'] = PythonLanguage 1756 1757 1758# maps strings to callables. 1759# these callables must be of the form: 1760# def foo(name, default, *, ...) 1761# The callable may have any number of keyword-only parameters. 1762# The callable must return a CConverter object. 1763# The callable should not call builtins.print. 1764converters = {} 1765 1766# maps strings to callables. 1767# these callables follow the same rules as those for "converters" above. 1768# note however that they will never be called with keyword-only parameters. 1769legacy_converters = {} 1770 1771 1772# maps strings to callables. 1773# these callables must be of the form: 1774# def foo(*, ...) 1775# The callable may have any number of keyword-only parameters. 1776# The callable must return a CConverter object. 1777# The callable should not call builtins.print. 1778return_converters = {} 1779 1780 1781def write_file(filename, new_contents): 1782 try: 1783 with open(filename, 'r', encoding="utf-8") as fp: 1784 old_contents = fp.read() 1785 1786 if old_contents == new_contents: 1787 # no change: avoid modifying the file modification time 1788 return 1789 except FileNotFoundError: 1790 pass 1791 1792 # Atomic write using a temporary file and os.replace() 1793 filename_new = f"{filename}.new" 1794 with open(filename_new, "w", encoding="utf-8") as fp: 1795 fp.write(new_contents) 1796 1797 try: 1798 os.replace(filename_new, filename) 1799 except: 1800 os.unlink(filename_new) 1801 raise 1802 1803 1804clinic = None 1805class Clinic: 1806 1807 presets_text = """ 1808preset block 1809everything block 1810methoddef_ifndef buffer 1 1811docstring_prototype suppress 1812parser_prototype suppress 1813cpp_if suppress 1814cpp_endif suppress 1815 1816preset original 1817everything block 1818methoddef_ifndef buffer 1 1819docstring_prototype suppress 1820parser_prototype suppress 1821cpp_if suppress 1822cpp_endif suppress 1823 1824preset file 1825everything file 1826methoddef_ifndef file 1 1827docstring_prototype suppress 1828parser_prototype suppress 1829impl_definition block 1830 1831preset buffer 1832everything buffer 1833methoddef_ifndef buffer 1 1834impl_definition block 1835docstring_prototype suppress 1836impl_prototype suppress 1837parser_prototype suppress 1838 1839preset partial-buffer 1840everything buffer 1841methoddef_ifndef buffer 1 1842docstring_prototype block 1843impl_prototype suppress 1844methoddef_define block 1845parser_prototype block 1846impl_definition block 1847 1848""" 1849 1850 def __init__(self, language, printer=None, *, verify=True, filename=None): 1851 # maps strings to Parser objects. 1852 # (instantiated from the "parsers" global.) 1853 self.parsers = {} 1854 self.language = language 1855 if printer: 1856 fail("Custom printers are broken right now") 1857 self.printer = printer or BlockPrinter(language) 1858 self.verify = verify 1859 self.filename = filename 1860 self.modules = collections.OrderedDict() 1861 self.classes = collections.OrderedDict() 1862 self.functions = [] 1863 1864 self.line_prefix = self.line_suffix = '' 1865 1866 self.destinations = {} 1867 self.add_destination("block", "buffer") 1868 self.add_destination("suppress", "suppress") 1869 self.add_destination("buffer", "buffer") 1870 if filename: 1871 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h") 1872 1873 d = self.get_destination_buffer 1874 self.destination_buffers = collections.OrderedDict(( 1875 ('cpp_if', d('file')), 1876 ('docstring_prototype', d('suppress')), 1877 ('docstring_definition', d('file')), 1878 ('methoddef_define', d('file')), 1879 ('impl_prototype', d('file')), 1880 ('parser_prototype', d('suppress')), 1881 ('parser_definition', d('file')), 1882 ('cpp_endif', d('file')), 1883 ('methoddef_ifndef', d('file', 1)), 1884 ('impl_definition', d('block')), 1885 )) 1886 1887 self.destination_buffers_stack = [] 1888 self.ifndef_symbols = set() 1889 1890 self.presets = {} 1891 preset = None 1892 for line in self.presets_text.strip().split('\n'): 1893 line = line.strip() 1894 if not line: 1895 continue 1896 name, value, *options = line.split() 1897 if name == 'preset': 1898 self.presets[value] = preset = collections.OrderedDict() 1899 continue 1900 1901 if len(options): 1902 index = int(options[0]) 1903 else: 1904 index = 0 1905 buffer = self.get_destination_buffer(value, index) 1906 1907 if name == 'everything': 1908 for name in self.destination_buffers: 1909 preset[name] = buffer 1910 continue 1911 1912 assert name in self.destination_buffers 1913 preset[name] = buffer 1914 1915 global clinic 1916 clinic = self 1917 1918 def add_destination(self, name, type, *args): 1919 if name in self.destinations: 1920 fail("Destination already exists: " + repr(name)) 1921 self.destinations[name] = Destination(name, type, self, *args) 1922 1923 def get_destination(self, name): 1924 d = self.destinations.get(name) 1925 if not d: 1926 fail("Destination does not exist: " + repr(name)) 1927 return d 1928 1929 def get_destination_buffer(self, name, item=0): 1930 d = self.get_destination(name) 1931 return d.buffers[item] 1932 1933 def parse(self, input): 1934 printer = self.printer 1935 self.block_parser = BlockParser(input, self.language, verify=self.verify) 1936 for block in self.block_parser: 1937 dsl_name = block.dsl_name 1938 if dsl_name: 1939 if dsl_name not in self.parsers: 1940 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name) 1941 self.parsers[dsl_name] = parsers[dsl_name](self) 1942 parser = self.parsers[dsl_name] 1943 try: 1944 parser.parse(block) 1945 except Exception: 1946 fail('Exception raised during parsing:\n' + 1947 traceback.format_exc().rstrip()) 1948 printer.print_block(block) 1949 1950 second_pass_replacements = {} 1951 1952 # these are destinations not buffers 1953 for name, destination in self.destinations.items(): 1954 if destination.type == 'suppress': 1955 continue 1956 output = destination.dump() 1957 1958 if output: 1959 1960 block = Block("", dsl_name="clinic", output=output) 1961 1962 if destination.type == 'buffer': 1963 block.input = "dump " + name + "\n" 1964 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.") 1965 printer.write("\n") 1966 printer.print_block(block) 1967 continue 1968 1969 if destination.type == 'file': 1970 try: 1971 dirname = os.path.dirname(destination.filename) 1972 try: 1973 os.makedirs(dirname) 1974 except FileExistsError: 1975 if not os.path.isdir(dirname): 1976 fail("Can't write to destination {}, " 1977 "can't make directory {}!".format( 1978 destination.filename, dirname)) 1979 if self.verify: 1980 with open(destination.filename, "rt") as f: 1981 parser_2 = BlockParser(f.read(), language=self.language) 1982 blocks = list(parser_2) 1983 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'): 1984 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!") 1985 except FileNotFoundError: 1986 pass 1987 1988 block.input = 'preserve\n' 1989 printer_2 = BlockPrinter(self.language) 1990 printer_2.print_block(block) 1991 write_file(destination.filename, printer_2.f.getvalue()) 1992 continue 1993 text = printer.f.getvalue() 1994 1995 if second_pass_replacements: 1996 printer_2 = BlockPrinter(self.language) 1997 parser_2 = BlockParser(text, self.language) 1998 changed = False 1999 for block in parser_2: 2000 if block.dsl_name: 2001 for id, replacement in second_pass_replacements.items(): 2002 if id in block.output: 2003 changed = True 2004 block.output = block.output.replace(id, replacement) 2005 printer_2.print_block(block) 2006 if changed: 2007 text = printer_2.f.getvalue() 2008 2009 return text 2010 2011 2012 def _module_and_class(self, fields): 2013 """ 2014 fields should be an iterable of field names. 2015 returns a tuple of (module, class). 2016 the module object could actually be self (a clinic object). 2017 this function is only ever used to find the parent of where 2018 a new class/module should go. 2019 """ 2020 in_classes = False 2021 parent = module = self 2022 cls = None 2023 so_far = [] 2024 2025 for field in fields: 2026 so_far.append(field) 2027 if not in_classes: 2028 child = parent.modules.get(field) 2029 if child: 2030 parent = module = child 2031 continue 2032 in_classes = True 2033 if not hasattr(parent, 'classes'): 2034 return module, cls 2035 child = parent.classes.get(field) 2036 if not child: 2037 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.") 2038 cls = parent = child 2039 2040 return module, cls 2041 2042 2043def parse_file(filename, *, verify=True, output=None): 2044 if not output: 2045 output = filename 2046 2047 extension = os.path.splitext(filename)[1][1:] 2048 if not extension: 2049 fail("Can't extract file type for file " + repr(filename)) 2050 2051 try: 2052 language = extensions[extension](filename) 2053 except KeyError: 2054 fail("Can't identify file type for file " + repr(filename)) 2055 2056 with open(filename, 'r', encoding="utf-8") as f: 2057 raw = f.read() 2058 2059 # exit quickly if there are no clinic markers in the file 2060 find_start_re = BlockParser("", language).find_start_re 2061 if not find_start_re.search(raw): 2062 return 2063 2064 clinic = Clinic(language, verify=verify, filename=filename) 2065 cooked = clinic.parse(raw) 2066 2067 write_file(output, cooked) 2068 2069 2070def compute_checksum(input, length=None): 2071 input = input or '' 2072 s = hashlib.sha1(input.encode('utf-8')).hexdigest() 2073 if length: 2074 s = s[:length] 2075 return s 2076 2077 2078 2079 2080class PythonParser: 2081 def __init__(self, clinic): 2082 pass 2083 2084 def parse(self, block): 2085 s = io.StringIO() 2086 with OverrideStdioWith(s): 2087 exec(block.input) 2088 block.output = s.getvalue() 2089 2090 2091class Module: 2092 def __init__(self, name, module=None): 2093 self.name = name 2094 self.module = self.parent = module 2095 2096 self.modules = collections.OrderedDict() 2097 self.classes = collections.OrderedDict() 2098 self.functions = [] 2099 2100 def __repr__(self): 2101 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">" 2102 2103class Class: 2104 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None): 2105 self.name = name 2106 self.module = module 2107 self.cls = cls 2108 self.typedef = typedef 2109 self.type_object = type_object 2110 self.parent = cls or module 2111 2112 self.classes = collections.OrderedDict() 2113 self.functions = [] 2114 2115 def __repr__(self): 2116 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">" 2117 2118unsupported_special_methods = set(""" 2119 2120__abs__ 2121__add__ 2122__and__ 2123__bytes__ 2124__call__ 2125__complex__ 2126__delitem__ 2127__divmod__ 2128__eq__ 2129__float__ 2130__floordiv__ 2131__ge__ 2132__getattr__ 2133__getattribute__ 2134__getitem__ 2135__gt__ 2136__hash__ 2137__iadd__ 2138__iand__ 2139__ifloordiv__ 2140__ilshift__ 2141__imatmul__ 2142__imod__ 2143__imul__ 2144__index__ 2145__int__ 2146__invert__ 2147__ior__ 2148__ipow__ 2149__irshift__ 2150__isub__ 2151__iter__ 2152__itruediv__ 2153__ixor__ 2154__le__ 2155__len__ 2156__lshift__ 2157__lt__ 2158__matmul__ 2159__mod__ 2160__mul__ 2161__neg__ 2162__new__ 2163__next__ 2164__or__ 2165__pos__ 2166__pow__ 2167__radd__ 2168__rand__ 2169__rdivmod__ 2170__repr__ 2171__rfloordiv__ 2172__rlshift__ 2173__rmatmul__ 2174__rmod__ 2175__rmul__ 2176__ror__ 2177__rpow__ 2178__rrshift__ 2179__rshift__ 2180__rsub__ 2181__rtruediv__ 2182__rxor__ 2183__setattr__ 2184__setitem__ 2185__str__ 2186__sub__ 2187__truediv__ 2188__xor__ 2189 2190""".strip().split()) 2191 2192 2193INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """ 2194INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW 2195""".replace(",", "").strip().split() 2196 2197class Function: 2198 """ 2199 Mutable duck type for inspect.Function. 2200 2201 docstring - a str containing 2202 * embedded line breaks 2203 * text outdented to the left margin 2204 * no trailing whitespace. 2205 It will always be true that 2206 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) 2207 """ 2208 2209 def __init__(self, parameters=None, *, name, 2210 module, cls=None, c_basename=None, 2211 full_name=None, 2212 return_converter, return_annotation=inspect.Signature.empty, 2213 docstring=None, kind=CALLABLE, coexist=False, 2214 docstring_only=False): 2215 self.parameters = parameters or collections.OrderedDict() 2216 self.return_annotation = return_annotation 2217 self.name = name 2218 self.full_name = full_name 2219 self.module = module 2220 self.cls = cls 2221 self.parent = cls or module 2222 self.c_basename = c_basename 2223 self.return_converter = return_converter 2224 self.docstring = docstring or '' 2225 self.kind = kind 2226 self.coexist = coexist 2227 self.self_converter = None 2228 # docstring_only means "don't generate a machine-readable 2229 # signature, just a normal docstring". it's True for 2230 # functions with optional groups because we can't represent 2231 # those accurately with inspect.Signature in 3.4. 2232 self.docstring_only = docstring_only 2233 2234 self.rendered_parameters = None 2235 2236 __render_parameters__ = None 2237 @property 2238 def render_parameters(self): 2239 if not self.__render_parameters__: 2240 self.__render_parameters__ = l = [] 2241 for p in self.parameters.values(): 2242 p = p.copy() 2243 p.converter.pre_render() 2244 l.append(p) 2245 return self.__render_parameters__ 2246 2247 @property 2248 def methoddef_flags(self): 2249 if self.kind in (METHOD_INIT, METHOD_NEW): 2250 return None 2251 flags = [] 2252 if self.kind == CLASS_METHOD: 2253 flags.append('METH_CLASS') 2254 elif self.kind == STATIC_METHOD: 2255 flags.append('METH_STATIC') 2256 else: 2257 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind) 2258 if self.coexist: 2259 flags.append('METH_COEXIST') 2260 return '|'.join(flags) 2261 2262 def __repr__(self): 2263 return '<clinic.Function ' + self.name + '>' 2264 2265 def copy(self, **overrides): 2266 kwargs = { 2267 'name': self.name, 'module': self.module, 'parameters': self.parameters, 2268 'cls': self.cls, 'c_basename': self.c_basename, 2269 'full_name': self.full_name, 2270 'return_converter': self.return_converter, 'return_annotation': self.return_annotation, 2271 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist, 2272 'docstring_only': self.docstring_only, 2273 } 2274 kwargs.update(overrides) 2275 f = Function(**kwargs) 2276 2277 parameters = collections.OrderedDict() 2278 for name, value in f.parameters.items(): 2279 value = value.copy(function=f) 2280 parameters[name] = value 2281 f.parameters = parameters 2282 return f 2283 2284 2285class Parameter: 2286 """ 2287 Mutable duck type of inspect.Parameter. 2288 """ 2289 2290 def __init__(self, name, kind, *, default=inspect.Parameter.empty, 2291 function, converter, annotation=inspect.Parameter.empty, 2292 docstring=None, group=0): 2293 self.name = name 2294 self.kind = kind 2295 self.default = default 2296 self.function = function 2297 self.converter = converter 2298 self.annotation = annotation 2299 self.docstring = docstring or '' 2300 self.group = group 2301 2302 def __repr__(self): 2303 return '<clinic.Parameter ' + self.name + '>' 2304 2305 def is_keyword_only(self): 2306 return self.kind == inspect.Parameter.KEYWORD_ONLY 2307 2308 def is_positional_only(self): 2309 return self.kind == inspect.Parameter.POSITIONAL_ONLY 2310 2311 def is_optional(self): 2312 return (self.default is not unspecified) 2313 2314 def copy(self, **overrides): 2315 kwargs = { 2316 'name': self.name, 'kind': self.kind, 'default':self.default, 2317 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, 2318 'docstring': self.docstring, 'group': self.group, 2319 } 2320 kwargs.update(overrides) 2321 if 'converter' not in overrides: 2322 converter = copy.copy(self.converter) 2323 converter.function = kwargs['function'] 2324 kwargs['converter'] = converter 2325 return Parameter(**kwargs) 2326 2327 def get_displayname(self, i): 2328 if i == 0: 2329 return '"argument"' 2330 if not self.is_positional_only(): 2331 return '''"argument '{}'"'''.format(self.name) 2332 else: 2333 return '"argument {}"'.format(i) 2334 2335 2336class LandMine: 2337 # try to access any 2338 def __init__(self, message): 2339 self.__message__ = message 2340 2341 def __repr__(self): 2342 return '<LandMine ' + repr(self.__message__) + ">" 2343 2344 def __getattribute__(self, name): 2345 if name in ('__repr__', '__message__'): 2346 return super().__getattribute__(name) 2347 # raise RuntimeError(repr(name)) 2348 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__) 2349 2350 2351def add_c_converter(f, name=None): 2352 if not name: 2353 name = f.__name__ 2354 if not name.endswith('_converter'): 2355 return f 2356 name = name[:-len('_converter')] 2357 converters[name] = f 2358 return f 2359 2360def add_default_legacy_c_converter(cls): 2361 # automatically add converter for default format unit 2362 # (but without stomping on the existing one if it's already 2363 # set, in case you subclass) 2364 if ((cls.format_unit not in ('O&', '')) and 2365 (cls.format_unit not in legacy_converters)): 2366 legacy_converters[cls.format_unit] = cls 2367 return cls 2368 2369def add_legacy_c_converter(format_unit, **kwargs): 2370 """ 2371 Adds a legacy converter. 2372 """ 2373 def closure(f): 2374 if not kwargs: 2375 added_f = f 2376 else: 2377 added_f = functools.partial(f, **kwargs) 2378 if format_unit: 2379 legacy_converters[format_unit] = added_f 2380 return f 2381 return closure 2382 2383class CConverterAutoRegister(type): 2384 def __init__(cls, name, bases, classdict): 2385 add_c_converter(cls) 2386 add_default_legacy_c_converter(cls) 2387 2388class CConverter(metaclass=CConverterAutoRegister): 2389 """ 2390 For the init function, self, name, function, and default 2391 must be keyword-or-positional parameters. All other 2392 parameters must be keyword-only. 2393 """ 2394 2395 # The C name to use for this variable. 2396 name = None 2397 2398 # The Python name to use for this variable. 2399 py_name = None 2400 2401 # The C type to use for this variable. 2402 # 'type' should be a Python string specifying the type, e.g. "int". 2403 # If this is a pointer type, the type string should end with ' *'. 2404 type = None 2405 2406 # The Python default value for this parameter, as a Python value. 2407 # Or the magic value "unspecified" if there is no default. 2408 # Or the magic value "unknown" if this value is a cannot be evaluated 2409 # at Argument-Clinic-preprocessing time (but is presumed to be valid 2410 # at runtime). 2411 default = unspecified 2412 2413 # If not None, default must be isinstance() of this type. 2414 # (You can also specify a tuple of types.) 2415 default_type = None 2416 2417 # "default" converted into a C value, as a string. 2418 # Or None if there is no default. 2419 c_default = None 2420 2421 # "default" converted into a Python value, as a string. 2422 # Or None if there is no default. 2423 py_default = None 2424 2425 # The default value used to initialize the C variable when 2426 # there is no default, but not specifying a default may 2427 # result in an "uninitialized variable" warning. This can 2428 # easily happen when using option groups--although 2429 # properly-written code won't actually use the variable, 2430 # the variable does get passed in to the _impl. (Ah, if 2431 # only dataflow analysis could inline the static function!) 2432 # 2433 # This value is specified as a string. 2434 # Every non-abstract subclass should supply a valid value. 2435 c_ignored_default = 'NULL' 2436 2437 # The C converter *function* to be used, if any. 2438 # (If this is not None, format_unit must be 'O&'.) 2439 converter = None 2440 2441 # Should Argument Clinic add a '&' before the name of 2442 # the variable when passing it into the _impl function? 2443 impl_by_reference = False 2444 2445 # Should Argument Clinic add a '&' before the name of 2446 # the variable when passing it into PyArg_ParseTuple (AndKeywords)? 2447 parse_by_reference = True 2448 2449 ############################################################# 2450 ############################################################# 2451 ## You shouldn't need to read anything below this point to ## 2452 ## write your own converter functions. ## 2453 ############################################################# 2454 ############################################################# 2455 2456 # The "format unit" to specify for this variable when 2457 # parsing arguments using PyArg_ParseTuple (AndKeywords). 2458 # Custom converters should always use the default value of 'O&'. 2459 format_unit = 'O&' 2460 2461 # What encoding do we want for this variable? Only used 2462 # by format units starting with 'e'. 2463 encoding = None 2464 2465 # Should this object be required to be a subclass of a specific type? 2466 # If not None, should be a string representing a pointer to a 2467 # PyTypeObject (e.g. "&PyUnicode_Type"). 2468 # Only used by the 'O!' format unit (and the "object" converter). 2469 subclass_of = None 2470 2471 # Do we want an adjacent '_length' variable for this variable? 2472 # Only used by format units ending with '#'. 2473 length = False 2474 2475 # Should we show this parameter in the generated 2476 # __text_signature__? This is *almost* always True. 2477 # (It's only False for __new__, __init__, and METH_STATIC functions.) 2478 show_in_signature = True 2479 2480 # Overrides the name used in a text signature. 2481 # The name used for a "self" parameter must be one of 2482 # self, type, or module; however users can set their own. 2483 # This lets the self_converter overrule the user-settable 2484 # name, *just* for the text signature. 2485 # Only set by self_converter. 2486 signature_name = None 2487 2488 # keep in sync with self_converter.__init__! 2489 def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs): 2490 self.name = ensure_legal_c_identifier(name) 2491 self.py_name = py_name 2492 2493 if default is not unspecified: 2494 if self.default_type and not isinstance(default, (self.default_type, Unknown)): 2495 if isinstance(self.default_type, type): 2496 types_str = self.default_type.__name__ 2497 else: 2498 types_str = ', '.join((cls.__name__ for cls in self.default_type)) 2499 fail("{}: default value {!r} for field {} is not of type {}".format( 2500 self.__class__.__name__, default, name, types_str)) 2501 self.default = default 2502 2503 if c_default: 2504 self.c_default = c_default 2505 if py_default: 2506 self.py_default = py_default 2507 2508 if annotation != unspecified: 2509 fail("The 'annotation' parameter is not currently permitted.") 2510 2511 # this is deliberate, to prevent you from caching information 2512 # about the function in the init. 2513 # (that breaks if we get cloned.) 2514 # so after this change we will noisily fail. 2515 self.function = LandMine("Don't access members of self.function inside converter_init!") 2516 self.converter_init(**kwargs) 2517 self.function = function 2518 2519 def converter_init(self): 2520 pass 2521 2522 def is_optional(self): 2523 return (self.default is not unspecified) 2524 2525 def _render_self(self, parameter, data): 2526 self.parameter = parameter 2527 name = self.name 2528 2529 # impl_arguments 2530 s = ("&" if self.impl_by_reference else "") + name 2531 data.impl_arguments.append(s) 2532 if self.length: 2533 data.impl_arguments.append(self.length_name()) 2534 2535 # impl_parameters 2536 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference)) 2537 if self.length: 2538 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name()) 2539 2540 def _render_non_self(self, parameter, data): 2541 self.parameter = parameter 2542 name = self.name 2543 2544 # declarations 2545 d = self.declaration() 2546 data.declarations.append(d) 2547 2548 # initializers 2549 initializers = self.initialize() 2550 if initializers: 2551 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip()) 2552 2553 # modifications 2554 modifications = self.modify() 2555 if modifications: 2556 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip()) 2557 2558 # keywords 2559 if parameter.is_positional_only(): 2560 data.keywords.append('') 2561 else: 2562 data.keywords.append(parameter.name) 2563 2564 # format_units 2565 if self.is_optional() and '|' not in data.format_units: 2566 data.format_units.append('|') 2567 if parameter.is_keyword_only() and '$' not in data.format_units: 2568 data.format_units.append('$') 2569 data.format_units.append(self.format_unit) 2570 2571 # parse_arguments 2572 self.parse_argument(data.parse_arguments) 2573 2574 # cleanup 2575 cleanup = self.cleanup() 2576 if cleanup: 2577 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") 2578 2579 def render(self, parameter, data): 2580 """ 2581 parameter is a clinic.Parameter instance. 2582 data is a CRenderData instance. 2583 """ 2584 self._render_self(parameter, data) 2585 self._render_non_self(parameter, data) 2586 2587 def length_name(self): 2588 """Computes the name of the associated "length" variable.""" 2589 if not self.length: 2590 return None 2591 return self.name + "_length" 2592 2593 # Why is this one broken out separately? 2594 # For "positional-only" function parsing, 2595 # which generates a bunch of PyArg_ParseTuple calls. 2596 def parse_argument(self, list): 2597 assert not (self.converter and self.encoding) 2598 if self.format_unit == 'O&': 2599 assert self.converter 2600 list.append(self.converter) 2601 2602 if self.encoding: 2603 list.append(c_repr(self.encoding)) 2604 elif self.subclass_of: 2605 list.append(self.subclass_of) 2606 2607 s = ("&" if self.parse_by_reference else "") + self.name 2608 list.append(s) 2609 2610 if self.length: 2611 list.append("&" + self.length_name()) 2612 2613 # 2614 # All the functions after here are intended as extension points. 2615 # 2616 2617 def simple_declaration(self, by_reference=False): 2618 """ 2619 Computes the basic declaration of the variable. 2620 Used in computing the prototype declaration and the 2621 variable declaration. 2622 """ 2623 prototype = [self.type] 2624 if by_reference or not self.type.endswith('*'): 2625 prototype.append(" ") 2626 if by_reference: 2627 prototype.append('*') 2628 prototype.append(self.name) 2629 return "".join(prototype) 2630 2631 def declaration(self): 2632 """ 2633 The C statement to declare this variable. 2634 """ 2635 declaration = [self.simple_declaration()] 2636 default = self.c_default 2637 if not default and self.parameter.group: 2638 default = self.c_ignored_default 2639 if default: 2640 declaration.append(" = ") 2641 declaration.append(default) 2642 declaration.append(";") 2643 if self.length: 2644 declaration.append('\nPy_ssize_clean_t ') 2645 declaration.append(self.length_name()) 2646 declaration.append(';') 2647 return "".join(declaration) 2648 2649 def initialize(self): 2650 """ 2651 The C statements required to set up this variable before parsing. 2652 Returns a string containing this code indented at column 0. 2653 If no initialization is necessary, returns an empty string. 2654 """ 2655 return "" 2656 2657 def modify(self): 2658 """ 2659 The C statements required to modify this variable after parsing. 2660 Returns a string containing this code indented at column 0. 2661 If no initialization is necessary, returns an empty string. 2662 """ 2663 return "" 2664 2665 def cleanup(self): 2666 """ 2667 The C statements required to clean up after this variable. 2668 Returns a string containing this code indented at column 0. 2669 If no cleanup is necessary, returns an empty string. 2670 """ 2671 return "" 2672 2673 def pre_render(self): 2674 """ 2675 A second initialization function, like converter_init, 2676 called just before rendering. 2677 You are permitted to examine self.function here. 2678 """ 2679 pass 2680 2681 def parse_arg(self, argname, displayname): 2682 if self.format_unit == 'O&': 2683 return """ 2684 if (!{converter}({argname}, &{paramname})) {{{{ 2685 goto exit; 2686 }}}} 2687 """.format(argname=argname, paramname=self.name, 2688 converter=self.converter) 2689 if self.format_unit == 'O!': 2690 cast = '(%s)' % self.type if self.type != 'PyObject *' else '' 2691 if self.subclass_of in type_checks: 2692 typecheck, typename = type_checks[self.subclass_of] 2693 return """ 2694 if (!{typecheck}({argname})) {{{{ 2695 _PyArg_BadArgument("{{name}}", {displayname}, "{typename}", {argname}); 2696 goto exit; 2697 }}}} 2698 {paramname} = {cast}{argname}; 2699 """.format(argname=argname, paramname=self.name, 2700 displayname=displayname, typecheck=typecheck, 2701 typename=typename, cast=cast) 2702 return """ 2703 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{ 2704 _PyArg_BadArgument("{{name}}", {displayname}, ({subclass_of})->tp_name, {argname}); 2705 goto exit; 2706 }}}} 2707 {paramname} = {cast}{argname}; 2708 """.format(argname=argname, paramname=self.name, 2709 subclass_of=self.subclass_of, cast=cast, 2710 displayname=displayname) 2711 if self.format_unit == 'O': 2712 cast = '(%s)' % self.type if self.type != 'PyObject *' else '' 2713 return """ 2714 {paramname} = {cast}{argname}; 2715 """.format(argname=argname, paramname=self.name, cast=cast) 2716 return None 2717 2718 def set_template_dict(self, template_dict): 2719 pass 2720 2721 2722type_checks = { 2723 '&PyLong_Type': ('PyLong_Check', 'int'), 2724 '&PyTuple_Type': ('PyTuple_Check', 'tuple'), 2725 '&PyList_Type': ('PyList_Check', 'list'), 2726 '&PySet_Type': ('PySet_Check', 'set'), 2727 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'), 2728 '&PyDict_Type': ('PyDict_Check', 'dict'), 2729 '&PyUnicode_Type': ('PyUnicode_Check', 'str'), 2730 '&PyBytes_Type': ('PyBytes_Check', 'bytes'), 2731 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'), 2732} 2733 2734 2735class bool_converter(CConverter): 2736 type = 'int' 2737 default_type = bool 2738 format_unit = 'p' 2739 c_ignored_default = '0' 2740 2741 def converter_init(self, *, accept={object}): 2742 if accept == {int}: 2743 self.format_unit = 'i' 2744 elif accept != {object}: 2745 fail("bool_converter: illegal 'accept' argument " + repr(accept)) 2746 if self.default is not unspecified: 2747 self.default = bool(self.default) 2748 self.c_default = str(int(self.default)) 2749 2750 def parse_arg(self, argname, displayname): 2751 if self.format_unit == 'i': 2752 # XXX PyFloat_Check can be removed after the end of the 2753 # deprecation in _PyLong_FromNbIndexOrNbInt. 2754 return """ 2755 if (PyFloat_Check({argname})) {{{{ 2756 PyErr_SetString(PyExc_TypeError, 2757 "integer argument expected, got float" ); 2758 goto exit; 2759 }}}} 2760 {paramname} = _PyLong_AsInt({argname}); 2761 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 2762 goto exit; 2763 }}}} 2764 """.format(argname=argname, paramname=self.name) 2765 elif self.format_unit == 'p': 2766 return """ 2767 {paramname} = PyObject_IsTrue({argname}); 2768 if ({paramname} < 0) {{{{ 2769 goto exit; 2770 }}}} 2771 """.format(argname=argname, paramname=self.name) 2772 return super().parse_arg(argname, displayname) 2773 2774class defining_class_converter(CConverter): 2775 """ 2776 A special-case converter: 2777 this is the default converter used for the defining class. 2778 """ 2779 type = 'PyTypeObject *' 2780 format_unit = '' 2781 show_in_signature = False 2782 2783 def converter_init(self, *, type=None): 2784 self.specified_type = type 2785 2786 def render(self, parameter, data): 2787 self._render_self(parameter, data) 2788 2789 def set_template_dict(self, template_dict): 2790 template_dict['defining_class_name'] = self.name 2791 2792 2793class char_converter(CConverter): 2794 type = 'char' 2795 default_type = (bytes, bytearray) 2796 format_unit = 'c' 2797 c_ignored_default = "'\0'" 2798 2799 def converter_init(self): 2800 if isinstance(self.default, self.default_type): 2801 if len(self.default) != 1: 2802 fail("char_converter: illegal default value " + repr(self.default)) 2803 2804 self.c_default = repr(bytes(self.default))[1:] 2805 if self.c_default == '"\'"': 2806 self.c_default = r"'\''" 2807 2808 def parse_arg(self, argname, displayname): 2809 if self.format_unit == 'c': 2810 return """ 2811 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{ 2812 {paramname} = PyBytes_AS_STRING({argname})[0]; 2813 }}}} 2814 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{ 2815 {paramname} = PyByteArray_AS_STRING({argname})[0]; 2816 }}}} 2817 else {{{{ 2818 _PyArg_BadArgument("{{name}}", {displayname}, "a byte string of length 1", {argname}); 2819 goto exit; 2820 }}}} 2821 """.format(argname=argname, paramname=self.name, 2822 displayname=displayname) 2823 return super().parse_arg(argname, displayname) 2824 2825 2826@add_legacy_c_converter('B', bitwise=True) 2827class unsigned_char_converter(CConverter): 2828 type = 'unsigned char' 2829 default_type = int 2830 format_unit = 'b' 2831 c_ignored_default = "'\0'" 2832 2833 def converter_init(self, *, bitwise=False): 2834 if bitwise: 2835 self.format_unit = 'B' 2836 2837 def parse_arg(self, argname, displayname): 2838 if self.format_unit == 'b': 2839 return """ 2840 if (PyFloat_Check({argname})) {{{{ 2841 PyErr_SetString(PyExc_TypeError, 2842 "integer argument expected, got float" ); 2843 goto exit; 2844 }}}} 2845 {{{{ 2846 long ival = PyLong_AsLong({argname}); 2847 if (ival == -1 && PyErr_Occurred()) {{{{ 2848 goto exit; 2849 }}}} 2850 else if (ival < 0) {{{{ 2851 PyErr_SetString(PyExc_OverflowError, 2852 "unsigned byte integer is less than minimum"); 2853 goto exit; 2854 }}}} 2855 else if (ival > UCHAR_MAX) {{{{ 2856 PyErr_SetString(PyExc_OverflowError, 2857 "unsigned byte integer is greater than maximum"); 2858 goto exit; 2859 }}}} 2860 else {{{{ 2861 {paramname} = (unsigned char) ival; 2862 }}}} 2863 }}}} 2864 """.format(argname=argname, paramname=self.name) 2865 elif self.format_unit == 'B': 2866 return """ 2867 if (PyFloat_Check({argname})) {{{{ 2868 PyErr_SetString(PyExc_TypeError, 2869 "integer argument expected, got float" ); 2870 goto exit; 2871 }}}} 2872 {{{{ 2873 long ival = PyLong_AsUnsignedLongMask({argname}); 2874 if (ival == -1 && PyErr_Occurred()) {{{{ 2875 goto exit; 2876 }}}} 2877 else {{{{ 2878 {paramname} = (unsigned char) ival; 2879 }}}} 2880 }}}} 2881 """.format(argname=argname, paramname=self.name) 2882 return super().parse_arg(argname, displayname) 2883 2884class byte_converter(unsigned_char_converter): pass 2885 2886class short_converter(CConverter): 2887 type = 'short' 2888 default_type = int 2889 format_unit = 'h' 2890 c_ignored_default = "0" 2891 2892 def parse_arg(self, argname, displayname): 2893 if self.format_unit == 'h': 2894 return """ 2895 if (PyFloat_Check({argname})) {{{{ 2896 PyErr_SetString(PyExc_TypeError, 2897 "integer argument expected, got float" ); 2898 goto exit; 2899 }}}} 2900 {{{{ 2901 long ival = PyLong_AsLong({argname}); 2902 if (ival == -1 && PyErr_Occurred()) {{{{ 2903 goto exit; 2904 }}}} 2905 else if (ival < SHRT_MIN) {{{{ 2906 PyErr_SetString(PyExc_OverflowError, 2907 "signed short integer is less than minimum"); 2908 goto exit; 2909 }}}} 2910 else if (ival > SHRT_MAX) {{{{ 2911 PyErr_SetString(PyExc_OverflowError, 2912 "signed short integer is greater than maximum"); 2913 goto exit; 2914 }}}} 2915 else {{{{ 2916 {paramname} = (short) ival; 2917 }}}} 2918 }}}} 2919 """.format(argname=argname, paramname=self.name) 2920 return super().parse_arg(argname, displayname) 2921 2922class unsigned_short_converter(CConverter): 2923 type = 'unsigned short' 2924 default_type = int 2925 c_ignored_default = "0" 2926 2927 def converter_init(self, *, bitwise=False): 2928 if bitwise: 2929 self.format_unit = 'H' 2930 else: 2931 self.converter = '_PyLong_UnsignedShort_Converter' 2932 2933 def parse_arg(self, argname, displayname): 2934 if self.format_unit == 'H': 2935 return """ 2936 if (PyFloat_Check({argname})) {{{{ 2937 PyErr_SetString(PyExc_TypeError, 2938 "integer argument expected, got float" ); 2939 goto exit; 2940 }}}} 2941 {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname}); 2942 if ({paramname} == (unsigned short)-1 && PyErr_Occurred()) {{{{ 2943 goto exit; 2944 }}}} 2945 """.format(argname=argname, paramname=self.name) 2946 return super().parse_arg(argname, displayname) 2947 2948@add_legacy_c_converter('C', accept={str}) 2949class int_converter(CConverter): 2950 type = 'int' 2951 default_type = int 2952 format_unit = 'i' 2953 c_ignored_default = "0" 2954 2955 def converter_init(self, *, accept={int}, type=None): 2956 if accept == {str}: 2957 self.format_unit = 'C' 2958 elif accept != {int}: 2959 fail("int_converter: illegal 'accept' argument " + repr(accept)) 2960 if type != None: 2961 self.type = type 2962 2963 def parse_arg(self, argname, displayname): 2964 if self.format_unit == 'i': 2965 return """ 2966 if (PyFloat_Check({argname})) {{{{ 2967 PyErr_SetString(PyExc_TypeError, 2968 "integer argument expected, got float" ); 2969 goto exit; 2970 }}}} 2971 {paramname} = _PyLong_AsInt({argname}); 2972 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 2973 goto exit; 2974 }}}} 2975 """.format(argname=argname, paramname=self.name) 2976 elif self.format_unit == 'C': 2977 return """ 2978 if (!PyUnicode_Check({argname})) {{{{ 2979 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname}); 2980 goto exit; 2981 }}}} 2982 if (PyUnicode_READY({argname})) {{{{ 2983 goto exit; 2984 }}}} 2985 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ 2986 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname}); 2987 goto exit; 2988 }}}} 2989 {paramname} = PyUnicode_READ_CHAR({argname}, 0); 2990 """.format(argname=argname, paramname=self.name, 2991 displayname=displayname) 2992 return super().parse_arg(argname, displayname) 2993 2994class unsigned_int_converter(CConverter): 2995 type = 'unsigned int' 2996 default_type = int 2997 c_ignored_default = "0" 2998 2999 def converter_init(self, *, bitwise=False): 3000 if bitwise: 3001 self.format_unit = 'I' 3002 else: 3003 self.converter = '_PyLong_UnsignedInt_Converter' 3004 3005 def parse_arg(self, argname, displayname): 3006 if self.format_unit == 'I': 3007 return """ 3008 if (PyFloat_Check({argname})) {{{{ 3009 PyErr_SetString(PyExc_TypeError, 3010 "integer argument expected, got float" ); 3011 goto exit; 3012 }}}} 3013 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname}); 3014 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{ 3015 goto exit; 3016 }}}} 3017 """.format(argname=argname, paramname=self.name) 3018 return super().parse_arg(argname, displayname) 3019 3020class long_converter(CConverter): 3021 type = 'long' 3022 default_type = int 3023 format_unit = 'l' 3024 c_ignored_default = "0" 3025 3026 def parse_arg(self, argname, displayname): 3027 if self.format_unit == 'l': 3028 return """ 3029 if (PyFloat_Check({argname})) {{{{ 3030 PyErr_SetString(PyExc_TypeError, 3031 "integer argument expected, got float" ); 3032 goto exit; 3033 }}}} 3034 {paramname} = PyLong_AsLong({argname}); 3035 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 3036 goto exit; 3037 }}}} 3038 """.format(argname=argname, paramname=self.name) 3039 return super().parse_arg(argname, displayname) 3040 3041class unsigned_long_converter(CConverter): 3042 type = 'unsigned long' 3043 default_type = int 3044 c_ignored_default = "0" 3045 3046 def converter_init(self, *, bitwise=False): 3047 if bitwise: 3048 self.format_unit = 'k' 3049 else: 3050 self.converter = '_PyLong_UnsignedLong_Converter' 3051 3052 def parse_arg(self, argname, displayname): 3053 if self.format_unit == 'k': 3054 return """ 3055 if (!PyLong_Check({argname})) {{{{ 3056 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname}); 3057 goto exit; 3058 }}}} 3059 {paramname} = PyLong_AsUnsignedLongMask({argname}); 3060 """.format(argname=argname, paramname=self.name, 3061 displayname=displayname) 3062 return super().parse_arg(argname, displayname) 3063 3064class long_long_converter(CConverter): 3065 type = 'long long' 3066 default_type = int 3067 format_unit = 'L' 3068 c_ignored_default = "0" 3069 3070 def parse_arg(self, argname, displayname): 3071 if self.format_unit == 'L': 3072 return """ 3073 if (PyFloat_Check({argname})) {{{{ 3074 PyErr_SetString(PyExc_TypeError, 3075 "integer argument expected, got float" ); 3076 goto exit; 3077 }}}} 3078 {paramname} = PyLong_AsLongLong({argname}); 3079 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 3080 goto exit; 3081 }}}} 3082 """.format(argname=argname, paramname=self.name) 3083 return super().parse_arg(argname, displayname) 3084 3085class unsigned_long_long_converter(CConverter): 3086 type = 'unsigned long long' 3087 default_type = int 3088 c_ignored_default = "0" 3089 3090 def converter_init(self, *, bitwise=False): 3091 if bitwise: 3092 self.format_unit = 'K' 3093 else: 3094 self.converter = '_PyLong_UnsignedLongLong_Converter' 3095 3096 def parse_arg(self, argname, displayname): 3097 if self.format_unit == 'K': 3098 return """ 3099 if (!PyLong_Check({argname})) {{{{ 3100 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname}); 3101 goto exit; 3102 }}}} 3103 {paramname} = PyLong_AsUnsignedLongLongMask({argname}); 3104 """.format(argname=argname, paramname=self.name, 3105 displayname=displayname) 3106 return super().parse_arg(argname, displayname) 3107 3108class Py_ssize_t_converter(CConverter): 3109 type = 'Py_ssize_t' 3110 c_ignored_default = "0" 3111 3112 def converter_init(self, *, accept={int}): 3113 if accept == {int}: 3114 self.format_unit = 'n' 3115 self.default_type = int 3116 elif accept == {int, NoneType}: 3117 self.converter = '_Py_convert_optional_to_ssize_t' 3118 else: 3119 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept)) 3120 3121 def parse_arg(self, argname, displayname): 3122 if self.format_unit == 'n': 3123 return """ 3124 if (PyFloat_Check({argname})) {{{{ 3125 PyErr_SetString(PyExc_TypeError, 3126 "integer argument expected, got float" ); 3127 goto exit; 3128 }}}} 3129 {{{{ 3130 Py_ssize_t ival = -1; 3131 PyObject *iobj = PyNumber_Index({argname}); 3132 if (iobj != NULL) {{{{ 3133 ival = PyLong_AsSsize_t(iobj); 3134 Py_DECREF(iobj); 3135 }}}} 3136 if (ival == -1 && PyErr_Occurred()) {{{{ 3137 goto exit; 3138 }}}} 3139 {paramname} = ival; 3140 }}}} 3141 """.format(argname=argname, paramname=self.name) 3142 return super().parse_arg(argname, displayname) 3143 3144 3145class slice_index_converter(CConverter): 3146 type = 'Py_ssize_t' 3147 3148 def converter_init(self, *, accept={int, NoneType}): 3149 if accept == {int}: 3150 self.converter = '_PyEval_SliceIndexNotNone' 3151 elif accept == {int, NoneType}: 3152 self.converter = '_PyEval_SliceIndex' 3153 else: 3154 fail("slice_index_converter: illegal 'accept' argument " + repr(accept)) 3155 3156class size_t_converter(CConverter): 3157 type = 'size_t' 3158 converter = '_PyLong_Size_t_Converter' 3159 c_ignored_default = "0" 3160 3161 def parse_arg(self, argname, displayname): 3162 if self.format_unit == 'n': 3163 return """ 3164 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError); 3165 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 3166 goto exit; 3167 }}}} 3168 """.format(argname=argname, paramname=self.name) 3169 return super().parse_arg(argname, displayname) 3170 3171 3172class float_converter(CConverter): 3173 type = 'float' 3174 default_type = float 3175 format_unit = 'f' 3176 c_ignored_default = "0.0" 3177 3178 def parse_arg(self, argname, displayname): 3179 if self.format_unit == 'f': 3180 return """ 3181 if (PyFloat_CheckExact({argname})) {{{{ 3182 {paramname} = (float) (PyFloat_AS_DOUBLE({argname})); 3183 }}}} 3184 else 3185 {{{{ 3186 {paramname} = (float) PyFloat_AsDouble({argname}); 3187 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{ 3188 goto exit; 3189 }}}} 3190 }}}} 3191 """.format(argname=argname, paramname=self.name) 3192 return super().parse_arg(argname, displayname) 3193 3194class double_converter(CConverter): 3195 type = 'double' 3196 default_type = float 3197 format_unit = 'd' 3198 c_ignored_default = "0.0" 3199 3200 def parse_arg(self, argname, displayname): 3201 if self.format_unit == 'd': 3202 return """ 3203 if (PyFloat_CheckExact({argname})) {{{{ 3204 {paramname} = PyFloat_AS_DOUBLE({argname}); 3205 }}}} 3206 else 3207 {{{{ 3208 {paramname} = PyFloat_AsDouble({argname}); 3209 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{ 3210 goto exit; 3211 }}}} 3212 }}}} 3213 """.format(argname=argname, paramname=self.name) 3214 return super().parse_arg(argname, displayname) 3215 3216 3217class Py_complex_converter(CConverter): 3218 type = 'Py_complex' 3219 default_type = complex 3220 format_unit = 'D' 3221 c_ignored_default = "{0.0, 0.0}" 3222 3223 def parse_arg(self, argname, displayname): 3224 if self.format_unit == 'D': 3225 return """ 3226 {paramname} = PyComplex_AsCComplex({argname}); 3227 if (PyErr_Occurred()) {{{{ 3228 goto exit; 3229 }}}} 3230 """.format(argname=argname, paramname=self.name) 3231 return super().parse_arg(argname, displayname) 3232 3233 3234class object_converter(CConverter): 3235 type = 'PyObject *' 3236 format_unit = 'O' 3237 3238 def converter_init(self, *, converter=None, type=None, subclass_of=None): 3239 if converter: 3240 if subclass_of: 3241 fail("object: Cannot pass in both 'converter' and 'subclass_of'") 3242 self.format_unit = 'O&' 3243 self.converter = converter 3244 elif subclass_of: 3245 self.format_unit = 'O!' 3246 self.subclass_of = subclass_of 3247 3248 if type is not None: 3249 self.type = type 3250 3251 3252# 3253# We define three conventions for buffer types in the 'accept' argument: 3254# 3255# buffer : any object supporting the buffer interface 3256# rwbuffer: any object supporting the buffer interface, but must be writeable 3257# robuffer: any object supporting the buffer interface, but must not be writeable 3258# 3259 3260class buffer: pass 3261class rwbuffer: pass 3262class robuffer: pass 3263 3264def str_converter_key(types, encoding, zeroes): 3265 return (frozenset(types), bool(encoding), bool(zeroes)) 3266 3267str_converter_argument_map = {} 3268 3269class str_converter(CConverter): 3270 type = 'const char *' 3271 default_type = (str, Null, NoneType) 3272 format_unit = 's' 3273 3274 def converter_init(self, *, accept={str}, encoding=None, zeroes=False): 3275 3276 key = str_converter_key(accept, encoding, zeroes) 3277 format_unit = str_converter_argument_map.get(key) 3278 if not format_unit: 3279 fail("str_converter: illegal combination of arguments", key) 3280 3281 self.format_unit = format_unit 3282 self.length = bool(zeroes) 3283 if encoding: 3284 if self.default not in (Null, None, unspecified): 3285 fail("str_converter: Argument Clinic doesn't support default values for encoded strings") 3286 self.encoding = encoding 3287 self.type = 'char *' 3288 # sorry, clinic can't support preallocated buffers 3289 # for es# and et# 3290 self.c_default = "NULL" 3291 if NoneType in accept and self.c_default == "Py_None": 3292 self.c_default = "NULL" 3293 3294 def cleanup(self): 3295 if self.encoding: 3296 name = self.name 3297 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"]) 3298 3299 def parse_arg(self, argname, displayname): 3300 if self.format_unit == 's': 3301 return """ 3302 if (!PyUnicode_Check({argname})) {{{{ 3303 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname}); 3304 goto exit; 3305 }}}} 3306 Py_ssize_t {paramname}_length; 3307 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length); 3308 if ({paramname} == NULL) {{{{ 3309 goto exit; 3310 }}}} 3311 if (strlen({paramname}) != (size_t){paramname}_length) {{{{ 3312 PyErr_SetString(PyExc_ValueError, "embedded null character"); 3313 goto exit; 3314 }}}} 3315 """.format(argname=argname, paramname=self.name, 3316 displayname=displayname) 3317 if self.format_unit == 'z': 3318 return """ 3319 if ({argname} == Py_None) {{{{ 3320 {paramname} = NULL; 3321 }}}} 3322 else if (PyUnicode_Check({argname})) {{{{ 3323 Py_ssize_t {paramname}_length; 3324 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length); 3325 if ({paramname} == NULL) {{{{ 3326 goto exit; 3327 }}}} 3328 if (strlen({paramname}) != (size_t){paramname}_length) {{{{ 3329 PyErr_SetString(PyExc_ValueError, "embedded null character"); 3330 goto exit; 3331 }}}} 3332 }}}} 3333 else {{{{ 3334 _PyArg_BadArgument("{{name}}", {displayname}, "str or None", {argname}); 3335 goto exit; 3336 }}}} 3337 """.format(argname=argname, paramname=self.name, 3338 displayname=displayname) 3339 return super().parse_arg(argname, displayname) 3340 3341# 3342# This is the fourth or fifth rewrite of registering all the 3343# string converter format units. Previous approaches hid 3344# bugs--generally mismatches between the semantics of the format 3345# unit and the arguments necessary to represent those semantics 3346# properly. Hopefully with this approach we'll get it 100% right. 3347# 3348# The r() function (short for "register") both registers the 3349# mapping from arguments to format unit *and* registers the 3350# legacy C converter for that format unit. 3351# 3352def r(format_unit, *, accept, encoding=False, zeroes=False): 3353 if not encoding and format_unit != 's': 3354 # add the legacy c converters here too. 3355 # 3356 # note: add_legacy_c_converter can't work for 3357 # es, es#, et, or et# 3358 # because of their extra encoding argument 3359 # 3360 # also don't add the converter for 's' because 3361 # the metaclass for CConverter adds it for us. 3362 kwargs = {} 3363 if accept != {str}: 3364 kwargs['accept'] = accept 3365 if zeroes: 3366 kwargs['zeroes'] = True 3367 added_f = functools.partial(str_converter, **kwargs) 3368 legacy_converters[format_unit] = added_f 3369 3370 d = str_converter_argument_map 3371 key = str_converter_key(accept, encoding, zeroes) 3372 if key in d: 3373 sys.exit("Duplicate keys specified for str_converter_argument_map!") 3374 d[key] = format_unit 3375 3376r('es', encoding=True, accept={str}) 3377r('es#', encoding=True, zeroes=True, accept={str}) 3378r('et', encoding=True, accept={bytes, bytearray, str}) 3379r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str}) 3380r('s', accept={str}) 3381r('s#', zeroes=True, accept={robuffer, str}) 3382r('y', accept={robuffer}) 3383r('y#', zeroes=True, accept={robuffer}) 3384r('z', accept={str, NoneType}) 3385r('z#', zeroes=True, accept={robuffer, str, NoneType}) 3386del r 3387 3388 3389class PyBytesObject_converter(CConverter): 3390 type = 'PyBytesObject *' 3391 format_unit = 'S' 3392 # accept = {bytes} 3393 3394 def parse_arg(self, argname, displayname): 3395 if self.format_unit == 'S': 3396 return """ 3397 if (!PyBytes_Check({argname})) {{{{ 3398 _PyArg_BadArgument("{{name}}", {displayname}, "bytes", {argname}); 3399 goto exit; 3400 }}}} 3401 {paramname} = ({type}){argname}; 3402 """.format(argname=argname, paramname=self.name, 3403 type=self.type, displayname=displayname) 3404 return super().parse_arg(argname, displayname) 3405 3406class PyByteArrayObject_converter(CConverter): 3407 type = 'PyByteArrayObject *' 3408 format_unit = 'Y' 3409 # accept = {bytearray} 3410 3411 def parse_arg(self, argname, displayname): 3412 if self.format_unit == 'Y': 3413 return """ 3414 if (!PyByteArray_Check({argname})) {{{{ 3415 _PyArg_BadArgument("{{name}}", {displayname}, "bytearray", {argname}); 3416 goto exit; 3417 }}}} 3418 {paramname} = ({type}){argname}; 3419 """.format(argname=argname, paramname=self.name, 3420 type=self.type, displayname=displayname) 3421 return super().parse_arg(argname, displayname) 3422 3423class unicode_converter(CConverter): 3424 type = 'PyObject *' 3425 default_type = (str, Null, NoneType) 3426 format_unit = 'U' 3427 3428 def parse_arg(self, argname, displayname): 3429 if self.format_unit == 'U': 3430 return """ 3431 if (!PyUnicode_Check({argname})) {{{{ 3432 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname}); 3433 goto exit; 3434 }}}} 3435 if (PyUnicode_READY({argname}) == -1) {{{{ 3436 goto exit; 3437 }}}} 3438 {paramname} = {argname}; 3439 """.format(argname=argname, paramname=self.name, 3440 displayname=displayname) 3441 return super().parse_arg(argname, displayname) 3442 3443@add_legacy_c_converter('u#', zeroes=True) 3444@add_legacy_c_converter('Z', accept={str, NoneType}) 3445@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True) 3446class Py_UNICODE_converter(CConverter): 3447 type = 'const Py_UNICODE *' 3448 default_type = (str, Null, NoneType) 3449 format_unit = 'u' 3450 3451 def converter_init(self, *, accept={str}, zeroes=False): 3452 format_unit = 'Z' if accept=={str, NoneType} else 'u' 3453 if zeroes: 3454 format_unit += '#' 3455 self.length = True 3456 self.format_unit = format_unit 3457 3458@add_legacy_c_converter('s*', accept={str, buffer}) 3459@add_legacy_c_converter('z*', accept={str, buffer, NoneType}) 3460@add_legacy_c_converter('w*', accept={rwbuffer}) 3461class Py_buffer_converter(CConverter): 3462 type = 'Py_buffer' 3463 format_unit = 'y*' 3464 impl_by_reference = True 3465 c_ignored_default = "{NULL, NULL}" 3466 3467 def converter_init(self, *, accept={buffer}): 3468 if self.default not in (unspecified, None): 3469 fail("The only legal default value for Py_buffer is None.") 3470 3471 self.c_default = self.c_ignored_default 3472 3473 if accept == {str, buffer, NoneType}: 3474 format_unit = 'z*' 3475 elif accept == {str, buffer}: 3476 format_unit = 's*' 3477 elif accept == {buffer}: 3478 format_unit = 'y*' 3479 elif accept == {rwbuffer}: 3480 format_unit = 'w*' 3481 else: 3482 fail("Py_buffer_converter: illegal combination of arguments") 3483 3484 self.format_unit = format_unit 3485 3486 def cleanup(self): 3487 name = self.name 3488 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"]) 3489 3490 def parse_arg(self, argname, displayname): 3491 if self.format_unit == 'y*': 3492 return """ 3493 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{ 3494 goto exit; 3495 }}}} 3496 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ 3497 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); 3498 goto exit; 3499 }}}} 3500 """.format(argname=argname, paramname=self.name, 3501 displayname=displayname) 3502 elif self.format_unit == 's*': 3503 return """ 3504 if (PyUnicode_Check({argname})) {{{{ 3505 Py_ssize_t len; 3506 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len); 3507 if (ptr == NULL) {{{{ 3508 goto exit; 3509 }}}} 3510 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0); 3511 }}}} 3512 else {{{{ /* any bytes-like object */ 3513 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{ 3514 goto exit; 3515 }}}} 3516 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ 3517 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); 3518 goto exit; 3519 }}}} 3520 }}}} 3521 """.format(argname=argname, paramname=self.name, 3522 displayname=displayname) 3523 elif self.format_unit == 'w*': 3524 return """ 3525 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{ 3526 PyErr_Clear(); 3527 _PyArg_BadArgument("{{name}}", {displayname}, "read-write bytes-like object", {argname}); 3528 goto exit; 3529 }}}} 3530 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ 3531 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); 3532 goto exit; 3533 }}}} 3534 """.format(argname=argname, paramname=self.name, 3535 displayname=displayname) 3536 return super().parse_arg(argname, displayname) 3537 3538 3539def correct_name_for_self(f): 3540 if f.kind in (CALLABLE, METHOD_INIT): 3541 if f.cls: 3542 return "PyObject *", "self" 3543 return "PyObject *", "module" 3544 if f.kind == STATIC_METHOD: 3545 return "void *", "null" 3546 if f.kind in (CLASS_METHOD, METHOD_NEW): 3547 return "PyTypeObject *", "type" 3548 raise RuntimeError("Unhandled type of function f: " + repr(f.kind)) 3549 3550def required_type_for_self_for_parser(f): 3551 type, _ = correct_name_for_self(f) 3552 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD): 3553 return type 3554 return None 3555 3556 3557class self_converter(CConverter): 3558 """ 3559 A special-case converter: 3560 this is the default converter used for "self". 3561 """ 3562 type = None 3563 format_unit = '' 3564 3565 def converter_init(self, *, type=None): 3566 self.specified_type = type 3567 3568 def pre_render(self): 3569 f = self.function 3570 default_type, default_name = correct_name_for_self(f) 3571 self.signature_name = default_name 3572 self.type = self.specified_type or self.type or default_type 3573 3574 kind = self.function.kind 3575 new_or_init = kind in (METHOD_NEW, METHOD_INIT) 3576 3577 if (kind == STATIC_METHOD) or new_or_init: 3578 self.show_in_signature = False 3579 3580 # tp_new (METHOD_NEW) functions are of type newfunc: 3581 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); 3582 # PyTypeObject is a typedef for struct _typeobject. 3583 # 3584 # tp_init (METHOD_INIT) functions are of type initproc: 3585 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *); 3586 # 3587 # All other functions generated by Argument Clinic are stored in 3588 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction: 3589 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); 3590 # However! We habitually cast these functions to PyCFunction, 3591 # since functions that accept keyword arguments don't fit this signature 3592 # but are stored there anyway. So strict type equality isn't important 3593 # for these functions. 3594 # 3595 # So: 3596 # 3597 # * The name of the first parameter to the impl and the parsing function will always 3598 # be self.name. 3599 # 3600 # * The type of the first parameter to the impl will always be of self.type. 3601 # 3602 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT): 3603 # * The type of the first parameter to the parsing function is also self.type. 3604 # This means that if you step into the parsing function, your "self" parameter 3605 # is of the correct type, which may make debugging more pleasant. 3606 # 3607 # * Else if the function is tp_new (METHOD_NEW): 3608 # * The type of the first parameter to the parsing function is "PyTypeObject *", 3609 # so the type signature of the function call is an exact match. 3610 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type 3611 # in the impl call. 3612 # 3613 # * Else if the function is tp_init (METHOD_INIT): 3614 # * The type of the first parameter to the parsing function is "PyObject *", 3615 # so the type signature of the function call is an exact match. 3616 # * If self.type != "PyObject *", we cast the first parameter to self.type 3617 # in the impl call. 3618 3619 @property 3620 def parser_type(self): 3621 return required_type_for_self_for_parser(self.function) or self.type 3622 3623 def render(self, parameter, data): 3624 """ 3625 parameter is a clinic.Parameter instance. 3626 data is a CRenderData instance. 3627 """ 3628 if self.function.kind == STATIC_METHOD: 3629 return 3630 3631 self._render_self(parameter, data) 3632 3633 if self.type != self.parser_type: 3634 # insert cast to impl_argument[0], aka self. 3635 # we know we're in the first slot in all the CRenderData lists, 3636 # because we render parameters in order, and self is always first. 3637 assert len(data.impl_arguments) == 1 3638 assert data.impl_arguments[0] == self.name 3639 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0] 3640 3641 def set_template_dict(self, template_dict): 3642 template_dict['self_name'] = self.name 3643 template_dict['self_type'] = self.parser_type 3644 kind = self.function.kind 3645 cls = self.function.cls 3646 3647 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef): 3648 type_object = self.function.cls.type_object 3649 if kind == METHOD_NEW: 3650 type_check = '({} == {})'.format(self.name, type_object) 3651 else: 3652 type_check = 'Py_IS_TYPE({}, {})'.format(self.name, type_object) 3653 3654 line = '{} &&\n '.format(type_check) 3655 template_dict['self_type_check'] = line 3656 3657 3658 3659def add_c_return_converter(f, name=None): 3660 if not name: 3661 name = f.__name__ 3662 if not name.endswith('_return_converter'): 3663 return f 3664 name = name[:-len('_return_converter')] 3665 return_converters[name] = f 3666 return f 3667 3668 3669class CReturnConverterAutoRegister(type): 3670 def __init__(cls, name, bases, classdict): 3671 add_c_return_converter(cls) 3672 3673class CReturnConverter(metaclass=CReturnConverterAutoRegister): 3674 3675 # The C type to use for this variable. 3676 # 'type' should be a Python string specifying the type, e.g. "int". 3677 # If this is a pointer type, the type string should end with ' *'. 3678 type = 'PyObject *' 3679 3680 # The Python default value for this parameter, as a Python value. 3681 # Or the magic value "unspecified" if there is no default. 3682 default = None 3683 3684 def __init__(self, *, py_default=None, **kwargs): 3685 self.py_default = py_default 3686 try: 3687 self.return_converter_init(**kwargs) 3688 except TypeError as e: 3689 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items()) 3690 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e)) 3691 3692 def return_converter_init(self): 3693 pass 3694 3695 def declare(self, data, name="_return_value"): 3696 line = [] 3697 add = line.append 3698 add(self.type) 3699 if not self.type.endswith('*'): 3700 add(' ') 3701 add(name + ';') 3702 data.declarations.append(''.join(line)) 3703 data.return_value = name 3704 3705 def err_occurred_if(self, expr, data): 3706 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr)) 3707 3708 def err_occurred_if_null_pointer(self, variable, data): 3709 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable)) 3710 3711 def render(self, function, data): 3712 """ 3713 function is a clinic.Function instance. 3714 data is a CRenderData instance. 3715 """ 3716 pass 3717 3718add_c_return_converter(CReturnConverter, 'object') 3719 3720class NoneType_return_converter(CReturnConverter): 3721 def render(self, function, data): 3722 self.declare(data) 3723 data.return_conversion.append(''' 3724if (_return_value != Py_None) { 3725 goto exit; 3726} 3727return_value = Py_None; 3728Py_INCREF(Py_None); 3729'''.strip()) 3730 3731class bool_return_converter(CReturnConverter): 3732 type = 'int' 3733 3734 def render(self, function, data): 3735 self.declare(data) 3736 self.err_occurred_if("_return_value == -1", data) 3737 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n') 3738 3739class long_return_converter(CReturnConverter): 3740 type = 'long' 3741 conversion_fn = 'PyLong_FromLong' 3742 cast = '' 3743 unsigned_cast = '' 3744 3745 def render(self, function, data): 3746 self.declare(data) 3747 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data) 3748 data.return_conversion.append( 3749 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n'))) 3750 3751class int_return_converter(long_return_converter): 3752 type = 'int' 3753 cast = '(long)' 3754 3755class init_return_converter(long_return_converter): 3756 """ 3757 Special return converter for __init__ functions. 3758 """ 3759 type = 'int' 3760 cast = '(long)' 3761 3762 def render(self, function, data): 3763 pass 3764 3765class unsigned_long_return_converter(long_return_converter): 3766 type = 'unsigned long' 3767 conversion_fn = 'PyLong_FromUnsignedLong' 3768 unsigned_cast = '(unsigned long)' 3769 3770class unsigned_int_return_converter(unsigned_long_return_converter): 3771 type = 'unsigned int' 3772 cast = '(unsigned long)' 3773 unsigned_cast = '(unsigned int)' 3774 3775class Py_ssize_t_return_converter(long_return_converter): 3776 type = 'Py_ssize_t' 3777 conversion_fn = 'PyLong_FromSsize_t' 3778 3779class size_t_return_converter(long_return_converter): 3780 type = 'size_t' 3781 conversion_fn = 'PyLong_FromSize_t' 3782 unsigned_cast = '(size_t)' 3783 3784 3785class double_return_converter(CReturnConverter): 3786 type = 'double' 3787 cast = '' 3788 3789 def render(self, function, data): 3790 self.declare(data) 3791 self.err_occurred_if("_return_value == -1.0", data) 3792 data.return_conversion.append( 3793 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n') 3794 3795class float_return_converter(double_return_converter): 3796 type = 'float' 3797 cast = '(double)' 3798 3799 3800def eval_ast_expr(node, globals, *, filename='-'): 3801 """ 3802 Takes an ast.Expr node. Compiles and evaluates it. 3803 Returns the result of the expression. 3804 3805 globals represents the globals dict the expression 3806 should see. (There's no equivalent for "locals" here.) 3807 """ 3808 3809 if isinstance(node, ast.Expr): 3810 node = node.value 3811 3812 node = ast.Expression(node) 3813 co = compile(node, filename, 'eval') 3814 fn = types.FunctionType(co, globals) 3815 return fn() 3816 3817 3818class IndentStack: 3819 def __init__(self): 3820 self.indents = [] 3821 self.margin = None 3822 3823 def _ensure(self): 3824 if not self.indents: 3825 fail('IndentStack expected indents, but none are defined.') 3826 3827 def measure(self, line): 3828 """ 3829 Returns the length of the line's margin. 3830 """ 3831 if '\t' in line: 3832 fail('Tab characters are illegal in the Argument Clinic DSL.') 3833 stripped = line.lstrip() 3834 if not len(stripped): 3835 # we can't tell anything from an empty line 3836 # so just pretend it's indented like our current indent 3837 self._ensure() 3838 return self.indents[-1] 3839 return len(line) - len(stripped) 3840 3841 def infer(self, line): 3842 """ 3843 Infer what is now the current margin based on this line. 3844 Returns: 3845 1 if we have indented (or this is the first margin) 3846 0 if the margin has not changed 3847 -N if we have dedented N times 3848 """ 3849 indent = self.measure(line) 3850 margin = ' ' * indent 3851 if not self.indents: 3852 self.indents.append(indent) 3853 self.margin = margin 3854 return 1 3855 current = self.indents[-1] 3856 if indent == current: 3857 return 0 3858 if indent > current: 3859 self.indents.append(indent) 3860 self.margin = margin 3861 return 1 3862 # indent < current 3863 if indent not in self.indents: 3864 fail("Illegal outdent.") 3865 outdent_count = 0 3866 while indent != current: 3867 self.indents.pop() 3868 current = self.indents[-1] 3869 outdent_count -= 1 3870 self.margin = margin 3871 return outdent_count 3872 3873 @property 3874 def depth(self): 3875 """ 3876 Returns how many margins are currently defined. 3877 """ 3878 return len(self.indents) 3879 3880 def indent(self, line): 3881 """ 3882 Indents a line by the currently defined margin. 3883 """ 3884 return self.margin + line 3885 3886 def dedent(self, line): 3887 """ 3888 Dedents a line by the currently defined margin. 3889 (The inverse of 'indent'.) 3890 """ 3891 margin = self.margin 3892 indent = self.indents[-1] 3893 if not line.startswith(margin): 3894 fail('Cannot dedent, line does not start with the previous margin:') 3895 return line[indent:] 3896 3897 3898class DSLParser: 3899 def __init__(self, clinic): 3900 self.clinic = clinic 3901 3902 self.directives = {} 3903 for name in dir(self): 3904 # functions that start with directive_ are added to directives 3905 _, s, key = name.partition("directive_") 3906 if s: 3907 self.directives[key] = getattr(self, name) 3908 3909 # functions that start with at_ are too, with an @ in front 3910 _, s, key = name.partition("at_") 3911 if s: 3912 self.directives['@' + key] = getattr(self, name) 3913 3914 self.reset() 3915 3916 def reset(self): 3917 self.function = None 3918 self.state = self.state_dsl_start 3919 self.parameter_indent = None 3920 self.keyword_only = False 3921 self.positional_only = False 3922 self.group = 0 3923 self.parameter_state = self.ps_start 3924 self.seen_positional_with_default = False 3925 self.indent = IndentStack() 3926 self.kind = CALLABLE 3927 self.coexist = False 3928 self.parameter_continuation = '' 3929 self.preserve_output = False 3930 3931 def directive_version(self, required): 3932 global version 3933 if version_comparitor(version, required) < 0: 3934 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required) 3935 3936 def directive_module(self, name): 3937 fields = name.split('.') 3938 new = fields.pop() 3939 module, cls = self.clinic._module_and_class(fields) 3940 if cls: 3941 fail("Can't nest a module inside a class!") 3942 3943 if name in module.classes: 3944 fail("Already defined module " + repr(name) + "!") 3945 3946 m = Module(name, module) 3947 module.modules[name] = m 3948 self.block.signatures.append(m) 3949 3950 def directive_class(self, name, typedef, type_object): 3951 fields = name.split('.') 3952 in_classes = False 3953 parent = self 3954 name = fields.pop() 3955 so_far = [] 3956 module, cls = self.clinic._module_and_class(fields) 3957 3958 parent = cls or module 3959 if name in parent.classes: 3960 fail("Already defined class " + repr(name) + "!") 3961 3962 c = Class(name, module, cls, typedef, type_object) 3963 parent.classes[name] = c 3964 self.block.signatures.append(c) 3965 3966 def directive_set(self, name, value): 3967 if name not in ("line_prefix", "line_suffix"): 3968 fail("unknown variable", repr(name)) 3969 3970 value = value.format_map({ 3971 'block comment start': '/*', 3972 'block comment end': '*/', 3973 }) 3974 3975 self.clinic.__dict__[name] = value 3976 3977 def directive_destination(self, name, command, *args): 3978 if command == 'new': 3979 self.clinic.add_destination(name, *args) 3980 return 3981 3982 if command == 'clear': 3983 self.clinic.get_destination(name).clear() 3984 fail("unknown destination command", repr(command)) 3985 3986 3987 def directive_output(self, command_or_name, destination=''): 3988 fd = self.clinic.destination_buffers 3989 3990 if command_or_name == "preset": 3991 preset = self.clinic.presets.get(destination) 3992 if not preset: 3993 fail("Unknown preset " + repr(destination) + "!") 3994 fd.update(preset) 3995 return 3996 3997 if command_or_name == "push": 3998 self.clinic.destination_buffers_stack.append(fd.copy()) 3999 return 4000 4001 if command_or_name == "pop": 4002 if not self.clinic.destination_buffers_stack: 4003 fail("Can't 'output pop', stack is empty!") 4004 previous_fd = self.clinic.destination_buffers_stack.pop() 4005 fd.update(previous_fd) 4006 return 4007 4008 # secret command for debugging! 4009 if command_or_name == "print": 4010 self.block.output.append(pprint.pformat(fd)) 4011 self.block.output.append('\n') 4012 return 4013 4014 d = self.clinic.get_destination(destination) 4015 4016 if command_or_name == "everything": 4017 for name in list(fd): 4018 fd[name] = d 4019 return 4020 4021 if command_or_name not in fd: 4022 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd)) 4023 fd[command_or_name] = d 4024 4025 def directive_dump(self, name): 4026 self.block.output.append(self.clinic.get_destination(name).dump()) 4027 4028 def directive_print(self, *args): 4029 self.block.output.append(' '.join(args)) 4030 self.block.output.append('\n') 4031 4032 def directive_preserve(self): 4033 if self.preserve_output: 4034 fail("Can't have preserve twice in one block!") 4035 self.preserve_output = True 4036 4037 def at_classmethod(self): 4038 if self.kind is not CALLABLE: 4039 fail("Can't set @classmethod, function is not a normal callable") 4040 self.kind = CLASS_METHOD 4041 4042 def at_staticmethod(self): 4043 if self.kind is not CALLABLE: 4044 fail("Can't set @staticmethod, function is not a normal callable") 4045 self.kind = STATIC_METHOD 4046 4047 def at_coexist(self): 4048 if self.coexist: 4049 fail("Called @coexist twice!") 4050 self.coexist = True 4051 4052 def parse(self, block): 4053 self.reset() 4054 self.block = block 4055 self.saved_output = self.block.output 4056 block.output = [] 4057 block_start = self.clinic.block_parser.line_number 4058 lines = block.input.split('\n') 4059 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number): 4060 if '\t' in line: 4061 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start) 4062 self.state(line) 4063 4064 self.next(self.state_terminal) 4065 self.state(None) 4066 4067 block.output.extend(self.clinic.language.render(clinic, block.signatures)) 4068 4069 if self.preserve_output: 4070 if block.output: 4071 fail("'preserve' only works for blocks that don't produce any output!") 4072 block.output = self.saved_output 4073 4074 @staticmethod 4075 def ignore_line(line): 4076 # ignore comment-only lines 4077 if line.lstrip().startswith('#'): 4078 return True 4079 4080 # Ignore empty lines too 4081 # (but not in docstring sections!) 4082 if not line.strip(): 4083 return True 4084 4085 return False 4086 4087 @staticmethod 4088 def calculate_indent(line): 4089 return len(line) - len(line.strip()) 4090 4091 def next(self, state, line=None): 4092 # real_print(self.state.__name__, "->", state.__name__, ", line=", line) 4093 self.state = state 4094 if line is not None: 4095 self.state(line) 4096 4097 def state_dsl_start(self, line): 4098 # self.block = self.ClinicOutputBlock(self) 4099 if self.ignore_line(line): 4100 return 4101 4102 # is it a directive? 4103 fields = shlex.split(line) 4104 directive_name = fields[0] 4105 directive = self.directives.get(directive_name, None) 4106 if directive: 4107 try: 4108 directive(*fields[1:]) 4109 except TypeError as e: 4110 fail(str(e)) 4111 return 4112 4113 self.next(self.state_modulename_name, line) 4114 4115 def state_modulename_name(self, line): 4116 # looking for declaration, which establishes the leftmost column 4117 # line should be 4118 # modulename.fnname [as c_basename] [-> return annotation] 4119 # square brackets denote optional syntax. 4120 # 4121 # alternatively: 4122 # modulename.fnname [as c_basename] = modulename.existing_fn_name 4123 # clones the parameters and return converter from that 4124 # function. you can't modify them. you must enter a 4125 # new docstring. 4126 # 4127 # (but we might find a directive first!) 4128 # 4129 # this line is permitted to start with whitespace. 4130 # we'll call this number of spaces F (for "function"). 4131 4132 if not line.strip(): 4133 return 4134 4135 self.indent.infer(line) 4136 4137 # are we cloning? 4138 before, equals, existing = line.rpartition('=') 4139 if equals: 4140 full_name, _, c_basename = before.partition(' as ') 4141 full_name = full_name.strip() 4142 c_basename = c_basename.strip() 4143 existing = existing.strip() 4144 if (is_legal_py_identifier(full_name) and 4145 (not c_basename or is_legal_c_identifier(c_basename)) and 4146 is_legal_py_identifier(existing)): 4147 # we're cloning! 4148 fields = [x.strip() for x in existing.split('.')] 4149 function_name = fields.pop() 4150 module, cls = self.clinic._module_and_class(fields) 4151 4152 for existing_function in (cls or module).functions: 4153 if existing_function.name == function_name: 4154 break 4155 else: 4156 existing_function = None 4157 if not existing_function: 4158 print("class", cls, "module", module, "existing", existing) 4159 print("cls. functions", cls.functions) 4160 fail("Couldn't find existing function " + repr(existing) + "!") 4161 4162 fields = [x.strip() for x in full_name.split('.')] 4163 function_name = fields.pop() 4164 module, cls = self.clinic._module_and_class(fields) 4165 4166 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist): 4167 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)") 4168 self.function = existing_function.copy(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, docstring='') 4169 4170 self.block.signatures.append(self.function) 4171 (cls or module).functions.append(self.function) 4172 self.next(self.state_function_docstring) 4173 return 4174 4175 line, _, returns = line.partition('->') 4176 4177 full_name, _, c_basename = line.partition(' as ') 4178 full_name = full_name.strip() 4179 c_basename = c_basename.strip() or None 4180 4181 if not is_legal_py_identifier(full_name): 4182 fail("Illegal function name: {}".format(full_name)) 4183 if c_basename and not is_legal_c_identifier(c_basename): 4184 fail("Illegal C basename: {}".format(c_basename)) 4185 4186 return_converter = None 4187 if returns: 4188 ast_input = "def x() -> {}: pass".format(returns) 4189 module = None 4190 try: 4191 module = ast.parse(ast_input) 4192 except SyntaxError: 4193 pass 4194 if not module: 4195 fail("Badly-formed annotation for " + full_name + ": " + returns) 4196 try: 4197 name, legacy, kwargs = self.parse_converter(module.body[0].returns) 4198 if legacy: 4199 fail("Legacy converter {!r} not allowed as a return converter" 4200 .format(name)) 4201 if name not in return_converters: 4202 fail("No available return converter called " + repr(name)) 4203 return_converter = return_converters[name](**kwargs) 4204 except ValueError: 4205 fail("Badly-formed annotation for " + full_name + ": " + returns) 4206 4207 fields = [x.strip() for x in full_name.split('.')] 4208 function_name = fields.pop() 4209 module, cls = self.clinic._module_and_class(fields) 4210 4211 fields = full_name.split('.') 4212 if fields[-1] == '__new__': 4213 if (self.kind != CLASS_METHOD) or (not cls): 4214 fail("__new__ must be a class method!") 4215 self.kind = METHOD_NEW 4216 elif fields[-1] == '__init__': 4217 if (self.kind != CALLABLE) or (not cls): 4218 fail("__init__ must be a normal method, not a class or static method!") 4219 self.kind = METHOD_INIT 4220 if not return_converter: 4221 return_converter = init_return_converter() 4222 elif fields[-1] in unsupported_special_methods: 4223 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)") 4224 4225 if not return_converter: 4226 return_converter = CReturnConverter() 4227 4228 if not module: 4229 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".") 4230 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, 4231 return_converter=return_converter, kind=self.kind, coexist=self.coexist) 4232 self.block.signatures.append(self.function) 4233 4234 # insert a self converter automatically 4235 type, name = correct_name_for_self(self.function) 4236 kwargs = {} 4237 if cls and type == "PyObject *": 4238 kwargs['type'] = cls.typedef 4239 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs) 4240 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc) 4241 self.function.parameters[sc.name] = p_self 4242 4243 (cls or module).functions.append(self.function) 4244 self.next(self.state_parameters_start) 4245 4246 # Now entering the parameters section. The rules, formally stated: 4247 # 4248 # * All lines must be indented with spaces only. 4249 # * The first line must be a parameter declaration. 4250 # * The first line must be indented. 4251 # * This first line establishes the indent for parameters. 4252 # * We'll call this number of spaces P (for "parameter"). 4253 # * Thenceforth: 4254 # * Lines indented with P spaces specify a parameter. 4255 # * Lines indented with > P spaces are docstrings for the previous 4256 # parameter. 4257 # * We'll call this number of spaces D (for "docstring"). 4258 # * All subsequent lines indented with >= D spaces are stored as 4259 # part of the per-parameter docstring. 4260 # * All lines will have the first D spaces of the indent stripped 4261 # before they are stored. 4262 # * It's illegal to have a line starting with a number of spaces X 4263 # such that P < X < D. 4264 # * A line with < P spaces is the first line of the function 4265 # docstring, which ends processing for parameters and per-parameter 4266 # docstrings. 4267 # * The first line of the function docstring must be at the same 4268 # indent as the function declaration. 4269 # * It's illegal to have any line in the parameters section starting 4270 # with X spaces such that F < X < P. (As before, F is the indent 4271 # of the function declaration.) 4272 # 4273 # Also, currently Argument Clinic places the following restrictions on groups: 4274 # * Each group must contain at least one parameter. 4275 # * Each group may contain at most one group, which must be the furthest 4276 # thing in the group from the required parameters. (The nested group 4277 # must be the first in the group when it's before the required 4278 # parameters, and the last thing in the group when after the required 4279 # parameters.) 4280 # * There may be at most one (top-level) group to the left or right of 4281 # the required parameters. 4282 # * You must specify a slash, and it must be after all parameters. 4283 # (In other words: either all parameters are positional-only, 4284 # or none are.) 4285 # 4286 # Said another way: 4287 # * Each group must contain at least one parameter. 4288 # * All left square brackets before the required parameters must be 4289 # consecutive. (You can't have a left square bracket followed 4290 # by a parameter, then another left square bracket. You can't 4291 # have a left square bracket, a parameter, a right square bracket, 4292 # and then a left square bracket.) 4293 # * All right square brackets after the required parameters must be 4294 # consecutive. 4295 # 4296 # These rules are enforced with a single state variable: 4297 # "parameter_state". (Previously the code was a miasma of ifs and 4298 # separate boolean state variables.) The states are: 4299 # 4300 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line 4301 # 01 2 3 4 5 6 <- state transitions 4302 # 4303 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3. 4304 # 1: ps_left_square_before. left square brackets before required parameters. 4305 # 2: ps_group_before. in a group, before required parameters. 4306 # 3: ps_required. required parameters, positional-or-keyword or positional-only 4307 # (we don't know yet). (renumber left groups!) 4308 # 4: ps_optional. positional-or-keyword or positional-only parameters that 4309 # now must have default values. 4310 # 5: ps_group_after. in a group, after required parameters. 4311 # 6: ps_right_square_after. right square brackets after required parameters. 4312 ps_start, ps_left_square_before, ps_group_before, ps_required, \ 4313 ps_optional, ps_group_after, ps_right_square_after = range(7) 4314 4315 def state_parameters_start(self, line): 4316 if self.ignore_line(line): 4317 return 4318 4319 # if this line is not indented, we have no parameters 4320 if not self.indent.infer(line): 4321 return self.next(self.state_function_docstring, line) 4322 4323 self.parameter_continuation = '' 4324 return self.next(self.state_parameter, line) 4325 4326 4327 def to_required(self): 4328 """ 4329 Transition to the "required" parameter state. 4330 """ 4331 if self.parameter_state != self.ps_required: 4332 self.parameter_state = self.ps_required 4333 for p in self.function.parameters.values(): 4334 p.group = -p.group 4335 4336 def state_parameter(self, line): 4337 if self.parameter_continuation: 4338 line = self.parameter_continuation + ' ' + line.lstrip() 4339 self.parameter_continuation = '' 4340 4341 if self.ignore_line(line): 4342 return 4343 4344 assert self.indent.depth == 2 4345 indent = self.indent.infer(line) 4346 if indent == -1: 4347 # we outdented, must be to definition column 4348 return self.next(self.state_function_docstring, line) 4349 4350 if indent == 1: 4351 # we indented, must be to new parameter docstring column 4352 return self.next(self.state_parameter_docstring_start, line) 4353 4354 line = line.rstrip() 4355 if line.endswith('\\'): 4356 self.parameter_continuation = line[:-1] 4357 return 4358 4359 line = line.lstrip() 4360 4361 if line in ('*', '/', '[', ']'): 4362 self.parse_special_symbol(line) 4363 return 4364 4365 if self.parameter_state in (self.ps_start, self.ps_required): 4366 self.to_required() 4367 elif self.parameter_state == self.ps_left_square_before: 4368 self.parameter_state = self.ps_group_before 4369 elif self.parameter_state == self.ps_group_before: 4370 if not self.group: 4371 self.to_required() 4372 elif self.parameter_state in (self.ps_group_after, self.ps_optional): 4373 pass 4374 else: 4375 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)") 4376 4377 # handle "as" for parameters too 4378 c_name = None 4379 name, have_as_token, trailing = line.partition(' as ') 4380 if have_as_token: 4381 name = name.strip() 4382 if ' ' not in name: 4383 fields = trailing.strip().split(' ') 4384 if not fields: 4385 fail("Invalid 'as' clause!") 4386 c_name = fields[0] 4387 if c_name.endswith(':'): 4388 name += ':' 4389 c_name = c_name[:-1] 4390 fields[0] = name 4391 line = ' '.join(fields) 4392 4393 base, equals, default = line.rpartition('=') 4394 if not equals: 4395 base = default 4396 default = None 4397 4398 module = None 4399 try: 4400 ast_input = "def x({}): pass".format(base) 4401 module = ast.parse(ast_input) 4402 except SyntaxError: 4403 try: 4404 # the last = was probably inside a function call, like 4405 # c: int(accept={str}) 4406 # so assume there was no actual default value. 4407 default = None 4408 ast_input = "def x({}): pass".format(line) 4409 module = ast.parse(ast_input) 4410 except SyntaxError: 4411 pass 4412 if not module: 4413 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line) 4414 4415 function_args = module.body[0].args 4416 4417 if len(function_args.args) > 1: 4418 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line) 4419 if function_args.defaults or function_args.kw_defaults: 4420 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line) 4421 if function_args.vararg or function_args.kwarg: 4422 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line) 4423 4424 parameter = function_args.args[0] 4425 4426 parameter_name = parameter.arg 4427 name, legacy, kwargs = self.parse_converter(parameter.annotation) 4428 4429 if not default: 4430 if self.parameter_state == self.ps_optional: 4431 fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!") 4432 value = unspecified 4433 if 'py_default' in kwargs: 4434 fail("You can't specify py_default without specifying a default value!") 4435 else: 4436 if self.parameter_state == self.ps_required: 4437 self.parameter_state = self.ps_optional 4438 default = default.strip() 4439 bad = False 4440 ast_input = "x = {}".format(default) 4441 bad = False 4442 try: 4443 module = ast.parse(ast_input) 4444 4445 if 'c_default' not in kwargs: 4446 # we can only represent very simple data values in C. 4447 # detect whether default is okay, via a blacklist 4448 # of disallowed ast nodes. 4449 class DetectBadNodes(ast.NodeVisitor): 4450 bad = False 4451 def bad_node(self, node): 4452 self.bad = True 4453 4454 # inline function call 4455 visit_Call = bad_node 4456 # inline if statement ("x = 3 if y else z") 4457 visit_IfExp = bad_node 4458 4459 # comprehensions and generator expressions 4460 visit_ListComp = visit_SetComp = bad_node 4461 visit_DictComp = visit_GeneratorExp = bad_node 4462 4463 # literals for advanced types 4464 visit_Dict = visit_Set = bad_node 4465 visit_List = visit_Tuple = bad_node 4466 4467 # "starred": "a = [1, 2, 3]; *a" 4468 visit_Starred = bad_node 4469 4470 blacklist = DetectBadNodes() 4471 blacklist.visit(module) 4472 bad = blacklist.bad 4473 else: 4474 # if they specify a c_default, we can be more lenient about the default value. 4475 # but at least make an attempt at ensuring it's a valid expression. 4476 try: 4477 value = eval(default) 4478 if value == unspecified: 4479 fail("'unspecified' is not a legal default value!") 4480 except NameError: 4481 pass # probably a named constant 4482 except Exception as e: 4483 fail("Malformed expression given as default value\n" 4484 "{!r} caused {!r}".format(default, e)) 4485 if bad: 4486 fail("Unsupported expression as default value: " + repr(default)) 4487 4488 expr = module.body[0].value 4489 # mild hack: explicitly support NULL as a default value 4490 if isinstance(expr, ast.Name) and expr.id == 'NULL': 4491 value = NULL 4492 py_default = '<unrepresentable>' 4493 c_default = "NULL" 4494 elif (isinstance(expr, ast.BinOp) or 4495 (isinstance(expr, ast.UnaryOp) and 4496 not (isinstance(expr.operand, ast.Num) or 4497 (hasattr(ast, 'Constant') and 4498 isinstance(expr.operand, ast.Constant) and 4499 type(expr.operand.value) in (int, float, complex))) 4500 )): 4501 c_default = kwargs.get("c_default") 4502 if not (isinstance(c_default, str) and c_default): 4503 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default." + ast.dump(expr)) 4504 py_default = default 4505 value = unknown 4506 elif isinstance(expr, ast.Attribute): 4507 a = [] 4508 n = expr 4509 while isinstance(n, ast.Attribute): 4510 a.append(n.attr) 4511 n = n.value 4512 if not isinstance(n, ast.Name): 4513 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)") 4514 a.append(n.id) 4515 py_default = ".".join(reversed(a)) 4516 4517 c_default = kwargs.get("c_default") 4518 if not (isinstance(c_default, str) and c_default): 4519 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") 4520 4521 try: 4522 value = eval(py_default) 4523 except NameError: 4524 value = unknown 4525 else: 4526 value = ast.literal_eval(expr) 4527 py_default = repr(value) 4528 if isinstance(value, (bool, None.__class__)): 4529 c_default = "Py_" + py_default 4530 elif isinstance(value, str): 4531 c_default = c_repr(value) 4532 else: 4533 c_default = py_default 4534 4535 except SyntaxError as e: 4536 fail("Syntax error: " + repr(e.text)) 4537 except (ValueError, AttributeError): 4538 value = unknown 4539 c_default = kwargs.get("c_default") 4540 py_default = default 4541 if not (isinstance(c_default, str) and c_default): 4542 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") 4543 4544 kwargs.setdefault('c_default', c_default) 4545 kwargs.setdefault('py_default', py_default) 4546 4547 dict = legacy_converters if legacy else converters 4548 legacy_str = "legacy " if legacy else "" 4549 if name not in dict: 4550 fail('{} is not a valid {}converter'.format(name, legacy_str)) 4551 # if you use a c_name for the parameter, we just give that name to the converter 4552 # but the parameter object gets the python name 4553 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs) 4554 4555 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD 4556 4557 if isinstance(converter, self_converter): 4558 if len(self.function.parameters) == 1: 4559 if (self.parameter_state != self.ps_required): 4560 fail("A 'self' parameter cannot be marked optional.") 4561 if value is not unspecified: 4562 fail("A 'self' parameter cannot have a default value.") 4563 if self.group: 4564 fail("A 'self' parameter cannot be in an optional group.") 4565 kind = inspect.Parameter.POSITIONAL_ONLY 4566 self.parameter_state = self.ps_start 4567 self.function.parameters.clear() 4568 else: 4569 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.") 4570 4571 if isinstance(converter, defining_class_converter): 4572 _lp = len(self.function.parameters) 4573 if _lp == 1: 4574 if (self.parameter_state != self.ps_required): 4575 fail("A 'defining_class' parameter cannot be marked optional.") 4576 if value is not unspecified: 4577 fail("A 'defining_class' parameter cannot have a default value.") 4578 if self.group: 4579 fail("A 'defining_class' parameter cannot be in an optional group.") 4580 else: 4581 fail("A 'defining_class' parameter, if specified, must either be the first thing in the parameter block, or come just after 'self'.") 4582 4583 4584 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group) 4585 4586 if parameter_name in self.function.parameters: 4587 fail("You can't have two parameters named " + repr(parameter_name) + "!") 4588 self.function.parameters[parameter_name] = p 4589 4590 def parse_converter(self, annotation): 4591 if (hasattr(ast, 'Constant') and 4592 isinstance(annotation, ast.Constant) and 4593 type(annotation.value) is str): 4594 return annotation.value, True, {} 4595 4596 if isinstance(annotation, ast.Str): 4597 return annotation.s, True, {} 4598 4599 if isinstance(annotation, ast.Name): 4600 return annotation.id, False, {} 4601 4602 if not isinstance(annotation, ast.Call): 4603 fail("Annotations must be either a name, a function call, or a string.") 4604 4605 name = annotation.func.id 4606 symbols = globals() 4607 4608 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords} 4609 return name, False, kwargs 4610 4611 def parse_special_symbol(self, symbol): 4612 if symbol == '*': 4613 if self.keyword_only: 4614 fail("Function " + self.function.name + " uses '*' more than once.") 4615 self.keyword_only = True 4616 elif symbol == '[': 4617 if self.parameter_state in (self.ps_start, self.ps_left_square_before): 4618 self.parameter_state = self.ps_left_square_before 4619 elif self.parameter_state in (self.ps_required, self.ps_group_after): 4620 self.parameter_state = self.ps_group_after 4621 else: 4622 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") 4623 self.group += 1 4624 self.function.docstring_only = True 4625 elif symbol == ']': 4626 if not self.group: 4627 fail("Function " + self.function.name + " has a ] without a matching [.") 4628 if not any(p.group == self.group for p in self.function.parameters.values()): 4629 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.") 4630 self.group -= 1 4631 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before): 4632 self.parameter_state = self.ps_group_before 4633 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after): 4634 self.parameter_state = self.ps_right_square_after 4635 else: 4636 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)") 4637 elif symbol == '/': 4638 if self.positional_only: 4639 fail("Function " + self.function.name + " uses '/' more than once.") 4640 self.positional_only = True 4641 # ps_required and ps_optional are allowed here, that allows positional-only without option groups 4642 # to work (and have default values!) 4643 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group: 4644 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)") 4645 if self.keyword_only: 4646 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") 4647 # fixup preceding parameters 4648 for p in self.function.parameters.values(): 4649 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)): 4650 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") 4651 p.kind = inspect.Parameter.POSITIONAL_ONLY 4652 4653 def state_parameter_docstring_start(self, line): 4654 self.parameter_docstring_indent = len(self.indent.margin) 4655 assert self.indent.depth == 3 4656 return self.next(self.state_parameter_docstring, line) 4657 4658 # every line of the docstring must start with at least F spaces, 4659 # where F > P. 4660 # these F spaces will be stripped. 4661 def state_parameter_docstring(self, line): 4662 stripped = line.strip() 4663 if stripped.startswith('#'): 4664 return 4665 4666 indent = self.indent.measure(line) 4667 if indent < self.parameter_docstring_indent: 4668 self.indent.infer(line) 4669 assert self.indent.depth < 3 4670 if self.indent.depth == 2: 4671 # back to a parameter 4672 return self.next(self.state_parameter, line) 4673 assert self.indent.depth == 1 4674 return self.next(self.state_function_docstring, line) 4675 4676 assert self.function.parameters 4677 last_parameter = next(reversed(list(self.function.parameters.values()))) 4678 4679 new_docstring = last_parameter.docstring 4680 4681 if new_docstring: 4682 new_docstring += '\n' 4683 if stripped: 4684 new_docstring += self.indent.dedent(line) 4685 4686 last_parameter.docstring = new_docstring 4687 4688 # the final stanza of the DSL is the docstring. 4689 def state_function_docstring(self, line): 4690 if self.group: 4691 fail("Function " + self.function.name + " has a ] without a matching [.") 4692 4693 stripped = line.strip() 4694 if stripped.startswith('#'): 4695 return 4696 4697 new_docstring = self.function.docstring 4698 if new_docstring: 4699 new_docstring += "\n" 4700 if stripped: 4701 line = self.indent.dedent(line).rstrip() 4702 else: 4703 line = '' 4704 new_docstring += line 4705 self.function.docstring = new_docstring 4706 4707 def format_docstring(self): 4708 f = self.function 4709 4710 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 4711 if new_or_init and not f.docstring: 4712 # don't render a docstring at all, no signature, nothing. 4713 return f.docstring 4714 4715 text, add, output = _text_accumulator() 4716 parameters = f.render_parameters 4717 4718 ## 4719 ## docstring first line 4720 ## 4721 4722 if new_or_init: 4723 # classes get *just* the name of the class 4724 # not __new__, not __init__, and not module.classname 4725 assert f.cls 4726 add(f.cls.name) 4727 else: 4728 add(f.name) 4729 add('(') 4730 4731 # populate "right_bracket_count" field for every parameter 4732 assert parameters, "We should always have a self parameter. " + repr(f) 4733 assert isinstance(parameters[0].converter, self_converter) 4734 # self is always positional-only. 4735 assert parameters[0].is_positional_only() 4736 parameters[0].right_bracket_count = 0 4737 positional_only = True 4738 for p in parameters[1:]: 4739 if not p.is_positional_only(): 4740 positional_only = False 4741 else: 4742 assert positional_only 4743 if positional_only: 4744 p.right_bracket_count = abs(p.group) 4745 else: 4746 # don't put any right brackets around non-positional-only parameters, ever. 4747 p.right_bracket_count = 0 4748 4749 right_bracket_count = 0 4750 4751 def fix_right_bracket_count(desired): 4752 nonlocal right_bracket_count 4753 s = '' 4754 while right_bracket_count < desired: 4755 s += '[' 4756 right_bracket_count += 1 4757 while right_bracket_count > desired: 4758 s += ']' 4759 right_bracket_count -= 1 4760 return s 4761 4762 need_slash = False 4763 added_slash = False 4764 need_a_trailing_slash = False 4765 4766 # we only need a trailing slash: 4767 # * if this is not a "docstring_only" signature 4768 # * and if the last *shown* parameter is 4769 # positional only 4770 if not f.docstring_only: 4771 for p in reversed(parameters): 4772 if not p.converter.show_in_signature: 4773 continue 4774 if p.is_positional_only(): 4775 need_a_trailing_slash = True 4776 break 4777 4778 4779 added_star = False 4780 4781 first_parameter = True 4782 last_p = parameters[-1] 4783 line_length = len(''.join(text)) 4784 indent = " " * line_length 4785 def add_parameter(text): 4786 nonlocal line_length 4787 nonlocal first_parameter 4788 if first_parameter: 4789 s = text 4790 first_parameter = False 4791 else: 4792 s = ' ' + text 4793 if line_length + len(s) >= 72: 4794 add('\n') 4795 add(indent) 4796 line_length = len(indent) 4797 s = text 4798 line_length += len(s) 4799 add(s) 4800 4801 for p in parameters: 4802 if not p.converter.show_in_signature: 4803 continue 4804 assert p.name 4805 4806 is_self = isinstance(p.converter, self_converter) 4807 if is_self and f.docstring_only: 4808 # this isn't a real machine-parsable signature, 4809 # so let's not print the "self" parameter 4810 continue 4811 4812 if p.is_positional_only(): 4813 need_slash = not f.docstring_only 4814 elif need_slash and not (added_slash or p.is_positional_only()): 4815 added_slash = True 4816 add_parameter('/,') 4817 4818 if p.is_keyword_only() and not added_star: 4819 added_star = True 4820 add_parameter('*,') 4821 4822 p_add, p_output = text_accumulator() 4823 p_add(fix_right_bracket_count(p.right_bracket_count)) 4824 4825 if isinstance(p.converter, self_converter): 4826 # annotate first parameter as being a "self". 4827 # 4828 # if inspect.Signature gets this function, 4829 # and it's already bound, the self parameter 4830 # will be stripped off. 4831 # 4832 # if it's not bound, it should be marked 4833 # as positional-only. 4834 # 4835 # note: we don't print "self" for __init__, 4836 # because this isn't actually the signature 4837 # for __init__. (it can't be, __init__ doesn't 4838 # have a docstring.) if this is an __init__ 4839 # (or __new__), then this signature is for 4840 # calling the class to construct a new instance. 4841 p_add('$') 4842 4843 name = p.converter.signature_name or p.name 4844 p_add(name) 4845 4846 if p.converter.is_optional(): 4847 p_add('=') 4848 value = p.converter.py_default 4849 if not value: 4850 value = repr(p.converter.default) 4851 p_add(value) 4852 4853 if (p != last_p) or need_a_trailing_slash: 4854 p_add(',') 4855 4856 add_parameter(p_output()) 4857 4858 add(fix_right_bracket_count(0)) 4859 if need_a_trailing_slash: 4860 add_parameter('/') 4861 add(')') 4862 4863 # PEP 8 says: 4864 # 4865 # The Python standard library will not use function annotations 4866 # as that would result in a premature commitment to a particular 4867 # annotation style. Instead, the annotations are left for users 4868 # to discover and experiment with useful annotation styles. 4869 # 4870 # therefore this is commented out: 4871 # 4872 # if f.return_converter.py_default: 4873 # add(' -> ') 4874 # add(f.return_converter.py_default) 4875 4876 if not f.docstring_only: 4877 add("\n" + sig_end_marker + "\n") 4878 4879 docstring_first_line = output() 4880 4881 # now fix up the places where the brackets look wrong 4882 docstring_first_line = docstring_first_line.replace(', ]', ',] ') 4883 4884 # okay. now we're officially building the "parameters" section. 4885 # create substitution text for {parameters} 4886 spacer_line = False 4887 for p in parameters: 4888 if not p.docstring.strip(): 4889 continue 4890 if spacer_line: 4891 add('\n') 4892 else: 4893 spacer_line = True 4894 add(" ") 4895 add(p.name) 4896 add('\n') 4897 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " ")) 4898 parameters = output() 4899 if parameters: 4900 parameters += '\n' 4901 4902 ## 4903 ## docstring body 4904 ## 4905 4906 docstring = f.docstring.rstrip() 4907 lines = [line.rstrip() for line in docstring.split('\n')] 4908 4909 # Enforce the summary line! 4910 # The first line of a docstring should be a summary of the function. 4911 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph 4912 # by itself. 4913 # 4914 # Argument Clinic enforces the following rule: 4915 # * either the docstring is empty, 4916 # * or it must have a summary line. 4917 # 4918 # Guido said Clinic should enforce this: 4919 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html 4920 4921 if len(lines) >= 2: 4922 if lines[1]: 4923 fail("Docstring for " + f.full_name + " does not have a summary line!\n" + 4924 "Every non-blank function docstring must start with\n" + 4925 "a single line summary followed by an empty line.") 4926 elif len(lines) == 1: 4927 # the docstring is only one line right now--the summary line. 4928 # add an empty line after the summary line so we have space 4929 # between it and the {parameters} we're about to add. 4930 lines.append('') 4931 4932 parameters_marker_count = len(docstring.split('{parameters}')) - 1 4933 if parameters_marker_count > 1: 4934 fail('You may not specify {parameters} more than once in a docstring!') 4935 4936 if not parameters_marker_count: 4937 # insert after summary line 4938 lines.insert(2, '{parameters}') 4939 4940 # insert at front of docstring 4941 lines.insert(0, docstring_first_line) 4942 4943 docstring = "\n".join(lines) 4944 4945 add(docstring) 4946 docstring = output() 4947 4948 docstring = linear_format(docstring, parameters=parameters) 4949 docstring = docstring.rstrip() 4950 4951 return docstring 4952 4953 def state_terminal(self, line): 4954 """ 4955 Called when processing the block is done. 4956 """ 4957 assert not line 4958 4959 if not self.function: 4960 return 4961 4962 if self.keyword_only: 4963 values = self.function.parameters.values() 4964 if not values: 4965 no_parameter_after_star = True 4966 else: 4967 last_parameter = next(reversed(list(values))) 4968 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY 4969 if no_parameter_after_star: 4970 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.") 4971 4972 # remove trailing whitespace from all parameter docstrings 4973 for name, value in self.function.parameters.items(): 4974 if not value: 4975 continue 4976 value.docstring = value.docstring.rstrip() 4977 4978 self.function.docstring = self.format_docstring() 4979 4980 4981 4982 4983# maps strings to callables. 4984# the callable should return an object 4985# that implements the clinic parser 4986# interface (__init__ and parse). 4987# 4988# example parsers: 4989# "clinic", handles the Clinic DSL 4990# "python", handles running Python code 4991# 4992parsers = {'clinic' : DSLParser, 'python': PythonParser} 4993 4994 4995clinic = None 4996 4997 4998def main(argv): 4999 import sys 5000 5001 if sys.version_info.major < 3 or sys.version_info.minor < 3: 5002 sys.exit("Error: clinic.py requires Python 3.3 or greater.") 5003 5004 import argparse 5005 cmdline = argparse.ArgumentParser( 5006 description="""Preprocessor for CPython C files. 5007 5008The purpose of the Argument Clinic is automating all the boilerplate involved 5009with writing argument parsing code for builtins and providing introspection 5010signatures ("docstrings") for CPython builtins. 5011 5012For more information see https://docs.python.org/3/howto/clinic.html""") 5013 cmdline.add_argument("-f", "--force", action='store_true') 5014 cmdline.add_argument("-o", "--output", type=str) 5015 cmdline.add_argument("-v", "--verbose", action='store_true') 5016 cmdline.add_argument("--converters", action='store_true') 5017 cmdline.add_argument("--make", action='store_true', 5018 help="Walk --srcdir to run over all relevant files.") 5019 cmdline.add_argument("--srcdir", type=str, default=os.curdir, 5020 help="The directory tree to walk in --make mode.") 5021 cmdline.add_argument("filename", type=str, nargs="*") 5022 ns = cmdline.parse_args(argv) 5023 5024 if ns.converters: 5025 if ns.filename: 5026 print("Usage error: can't specify --converters and a filename at the same time.") 5027 print() 5028 cmdline.print_usage() 5029 sys.exit(-1) 5030 converters = [] 5031 return_converters = [] 5032 ignored = set(""" 5033 add_c_converter 5034 add_c_return_converter 5035 add_default_legacy_c_converter 5036 add_legacy_c_converter 5037 """.strip().split()) 5038 module = globals() 5039 for name in module: 5040 for suffix, ids in ( 5041 ("_return_converter", return_converters), 5042 ("_converter", converters), 5043 ): 5044 if name in ignored: 5045 continue 5046 if name.endswith(suffix): 5047 ids.append((name, name[:-len(suffix)])) 5048 break 5049 print() 5050 5051 print("Legacy converters:") 5052 legacy = sorted(legacy_converters) 5053 print(' ' + ' '.join(c for c in legacy if c[0].isupper())) 5054 print(' ' + ' '.join(c for c in legacy if c[0].islower())) 5055 print() 5056 5057 for title, attribute, ids in ( 5058 ("Converters", 'converter_init', converters), 5059 ("Return converters", 'return_converter_init', return_converters), 5060 ): 5061 print(title + ":") 5062 longest = -1 5063 for name, short_name in ids: 5064 longest = max(longest, len(short_name)) 5065 for name, short_name in sorted(ids, key=lambda x: x[1].lower()): 5066 cls = module[name] 5067 callable = getattr(cls, attribute, None) 5068 if not callable: 5069 continue 5070 signature = inspect.signature(callable) 5071 parameters = [] 5072 for parameter_name, parameter in signature.parameters.items(): 5073 if parameter.kind == inspect.Parameter.KEYWORD_ONLY: 5074 if parameter.default != inspect.Parameter.empty: 5075 s = '{}={!r}'.format(parameter_name, parameter.default) 5076 else: 5077 s = parameter_name 5078 parameters.append(s) 5079 print(' {}({})'.format(short_name, ', '.join(parameters))) 5080 print() 5081 print("All converters also accept (c_default=None, py_default=None, annotation=None).") 5082 print("All return converters also accept (py_default=None).") 5083 sys.exit(0) 5084 5085 if ns.make: 5086 if ns.output or ns.filename: 5087 print("Usage error: can't use -o or filenames with --make.") 5088 print() 5089 cmdline.print_usage() 5090 sys.exit(-1) 5091 if not ns.srcdir: 5092 print("Usage error: --srcdir must not be empty with --make.") 5093 print() 5094 cmdline.print_usage() 5095 sys.exit(-1) 5096 for root, dirs, files in os.walk(ns.srcdir): 5097 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'): 5098 if rcs_dir in dirs: 5099 dirs.remove(rcs_dir) 5100 for filename in files: 5101 if not (filename.endswith('.c') or filename.endswith('.h')): 5102 continue 5103 path = os.path.join(root, filename) 5104 if ns.verbose: 5105 print(path) 5106 parse_file(path, verify=not ns.force) 5107 return 5108 5109 if not ns.filename: 5110 cmdline.print_usage() 5111 sys.exit(-1) 5112 5113 if ns.output and len(ns.filename) > 1: 5114 print("Usage error: can't use -o with multiple filenames.") 5115 print() 5116 cmdline.print_usage() 5117 sys.exit(-1) 5118 5119 for filename in ns.filename: 5120 if ns.verbose: 5121 print(filename) 5122 parse_file(filename, output=ns.output, verify=not ns.force) 5123 5124 5125if __name__ == "__main__": 5126 sys.exit(main(sys.argv[1:])) 5127