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 is None) ^ (output is 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__next__ 2163__or__ 2164__pos__ 2165__pow__ 2166__radd__ 2167__rand__ 2168__rdivmod__ 2169__repr__ 2170__rfloordiv__ 2171__rlshift__ 2172__rmatmul__ 2173__rmod__ 2174__rmul__ 2175__ror__ 2176__rpow__ 2177__rrshift__ 2178__rshift__ 2179__rsub__ 2180__rtruediv__ 2181__rxor__ 2182__setattr__ 2183__setitem__ 2184__str__ 2185__sub__ 2186__truediv__ 2187__xor__ 2188 2189""".strip().split()) 2190 2191 2192INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """ 2193INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW 2194""".replace(",", "").strip().split() 2195 2196class Function: 2197 """ 2198 Mutable duck type for inspect.Function. 2199 2200 docstring - a str containing 2201 * embedded line breaks 2202 * text outdented to the left margin 2203 * no trailing whitespace. 2204 It will always be true that 2205 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) 2206 """ 2207 2208 def __init__(self, parameters=None, *, name, 2209 module, cls=None, c_basename=None, 2210 full_name=None, 2211 return_converter, return_annotation=inspect.Signature.empty, 2212 docstring=None, kind=CALLABLE, coexist=False, 2213 docstring_only=False): 2214 self.parameters = parameters or collections.OrderedDict() 2215 self.return_annotation = return_annotation 2216 self.name = name 2217 self.full_name = full_name 2218 self.module = module 2219 self.cls = cls 2220 self.parent = cls or module 2221 self.c_basename = c_basename 2222 self.return_converter = return_converter 2223 self.docstring = docstring or '' 2224 self.kind = kind 2225 self.coexist = coexist 2226 self.self_converter = None 2227 # docstring_only means "don't generate a machine-readable 2228 # signature, just a normal docstring". it's True for 2229 # functions with optional groups because we can't represent 2230 # those accurately with inspect.Signature in 3.4. 2231 self.docstring_only = docstring_only 2232 2233 self.rendered_parameters = None 2234 2235 __render_parameters__ = None 2236 @property 2237 def render_parameters(self): 2238 if not self.__render_parameters__: 2239 self.__render_parameters__ = l = [] 2240 for p in self.parameters.values(): 2241 p = p.copy() 2242 p.converter.pre_render() 2243 l.append(p) 2244 return self.__render_parameters__ 2245 2246 @property 2247 def methoddef_flags(self): 2248 if self.kind in (METHOD_INIT, METHOD_NEW): 2249 return None 2250 flags = [] 2251 if self.kind == CLASS_METHOD: 2252 flags.append('METH_CLASS') 2253 elif self.kind == STATIC_METHOD: 2254 flags.append('METH_STATIC') 2255 else: 2256 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind) 2257 if self.coexist: 2258 flags.append('METH_COEXIST') 2259 return '|'.join(flags) 2260 2261 def __repr__(self): 2262 return '<clinic.Function ' + self.name + '>' 2263 2264 def copy(self, **overrides): 2265 kwargs = { 2266 'name': self.name, 'module': self.module, 'parameters': self.parameters, 2267 'cls': self.cls, 'c_basename': self.c_basename, 2268 'full_name': self.full_name, 2269 'return_converter': self.return_converter, 'return_annotation': self.return_annotation, 2270 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist, 2271 'docstring_only': self.docstring_only, 2272 } 2273 kwargs.update(overrides) 2274 f = Function(**kwargs) 2275 2276 parameters = collections.OrderedDict() 2277 for name, value in f.parameters.items(): 2278 value = value.copy(function=f) 2279 parameters[name] = value 2280 f.parameters = parameters 2281 return f 2282 2283 2284class Parameter: 2285 """ 2286 Mutable duck type of inspect.Parameter. 2287 """ 2288 2289 def __init__(self, name, kind, *, default=inspect.Parameter.empty, 2290 function, converter, annotation=inspect.Parameter.empty, 2291 docstring=None, group=0): 2292 self.name = name 2293 self.kind = kind 2294 self.default = default 2295 self.function = function 2296 self.converter = converter 2297 self.annotation = annotation 2298 self.docstring = docstring or '' 2299 self.group = group 2300 2301 def __repr__(self): 2302 return '<clinic.Parameter ' + self.name + '>' 2303 2304 def is_keyword_only(self): 2305 return self.kind == inspect.Parameter.KEYWORD_ONLY 2306 2307 def is_positional_only(self): 2308 return self.kind == inspect.Parameter.POSITIONAL_ONLY 2309 2310 def is_optional(self): 2311 return (self.default is not unspecified) 2312 2313 def copy(self, **overrides): 2314 kwargs = { 2315 'name': self.name, 'kind': self.kind, 'default':self.default, 2316 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, 2317 'docstring': self.docstring, 'group': self.group, 2318 } 2319 kwargs.update(overrides) 2320 if 'converter' not in overrides: 2321 converter = copy.copy(self.converter) 2322 converter.function = kwargs['function'] 2323 kwargs['converter'] = converter 2324 return Parameter(**kwargs) 2325 2326 def get_displayname(self, i): 2327 if i == 0: 2328 return '"argument"' 2329 if not self.is_positional_only(): 2330 return '''"argument '{}'"'''.format(self.name) 2331 else: 2332 return '"argument {}"'.format(i) 2333 2334 2335class LandMine: 2336 # try to access any 2337 def __init__(self, message): 2338 self.__message__ = message 2339 2340 def __repr__(self): 2341 return '<LandMine ' + repr(self.__message__) + ">" 2342 2343 def __getattribute__(self, name): 2344 if name in ('__repr__', '__message__'): 2345 return super().__getattribute__(name) 2346 # raise RuntimeError(repr(name)) 2347 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__) 2348 2349 2350def add_c_converter(f, name=None): 2351 if not name: 2352 name = f.__name__ 2353 if not name.endswith('_converter'): 2354 return f 2355 name = name[:-len('_converter')] 2356 converters[name] = f 2357 return f 2358 2359def add_default_legacy_c_converter(cls): 2360 # automatically add converter for default format unit 2361 # (but without stomping on the existing one if it's already 2362 # set, in case you subclass) 2363 if ((cls.format_unit not in ('O&', '')) and 2364 (cls.format_unit not in legacy_converters)): 2365 legacy_converters[cls.format_unit] = cls 2366 return cls 2367 2368def add_legacy_c_converter(format_unit, **kwargs): 2369 """ 2370 Adds a legacy converter. 2371 """ 2372 def closure(f): 2373 if not kwargs: 2374 added_f = f 2375 else: 2376 added_f = functools.partial(f, **kwargs) 2377 if format_unit: 2378 legacy_converters[format_unit] = added_f 2379 return f 2380 return closure 2381 2382class CConverterAutoRegister(type): 2383 def __init__(cls, name, bases, classdict): 2384 add_c_converter(cls) 2385 add_default_legacy_c_converter(cls) 2386 2387class CConverter(metaclass=CConverterAutoRegister): 2388 """ 2389 For the init function, self, name, function, and default 2390 must be keyword-or-positional parameters. All other 2391 parameters must be keyword-only. 2392 """ 2393 2394 # The C name to use for this variable. 2395 name = None 2396 2397 # The Python name to use for this variable. 2398 py_name = None 2399 2400 # The C type to use for this variable. 2401 # 'type' should be a Python string specifying the type, e.g. "int". 2402 # If this is a pointer type, the type string should end with ' *'. 2403 type = None 2404 2405 # The Python default value for this parameter, as a Python value. 2406 # Or the magic value "unspecified" if there is no default. 2407 # Or the magic value "unknown" if this value is a cannot be evaluated 2408 # at Argument-Clinic-preprocessing time (but is presumed to be valid 2409 # at runtime). 2410 default = unspecified 2411 2412 # If not None, default must be isinstance() of this type. 2413 # (You can also specify a tuple of types.) 2414 default_type = None 2415 2416 # "default" converted into a C value, as a string. 2417 # Or None if there is no default. 2418 c_default = None 2419 2420 # "default" converted into a Python value, as a string. 2421 # Or None if there is no default. 2422 py_default = None 2423 2424 # The default value used to initialize the C variable when 2425 # there is no default, but not specifying a default may 2426 # result in an "uninitialized variable" warning. This can 2427 # easily happen when using option groups--although 2428 # properly-written code won't actually use the variable, 2429 # the variable does get passed in to the _impl. (Ah, if 2430 # only dataflow analysis could inline the static function!) 2431 # 2432 # This value is specified as a string. 2433 # Every non-abstract subclass should supply a valid value. 2434 c_ignored_default = 'NULL' 2435 2436 # The C converter *function* to be used, if any. 2437 # (If this is not None, format_unit must be 'O&'.) 2438 converter = None 2439 2440 # Should Argument Clinic add a '&' before the name of 2441 # the variable when passing it into the _impl function? 2442 impl_by_reference = False 2443 2444 # Should Argument Clinic add a '&' before the name of 2445 # the variable when passing it into PyArg_ParseTuple (AndKeywords)? 2446 parse_by_reference = True 2447 2448 ############################################################# 2449 ############################################################# 2450 ## You shouldn't need to read anything below this point to ## 2451 ## write your own converter functions. ## 2452 ############################################################# 2453 ############################################################# 2454 2455 # The "format unit" to specify for this variable when 2456 # parsing arguments using PyArg_ParseTuple (AndKeywords). 2457 # Custom converters should always use the default value of 'O&'. 2458 format_unit = 'O&' 2459 2460 # What encoding do we want for this variable? Only used 2461 # by format units starting with 'e'. 2462 encoding = None 2463 2464 # Should this object be required to be a subclass of a specific type? 2465 # If not None, should be a string representing a pointer to a 2466 # PyTypeObject (e.g. "&PyUnicode_Type"). 2467 # Only used by the 'O!' format unit (and the "object" converter). 2468 subclass_of = None 2469 2470 # Do we want an adjacent '_length' variable for this variable? 2471 # Only used by format units ending with '#'. 2472 length = False 2473 2474 # Should we show this parameter in the generated 2475 # __text_signature__? This is *almost* always True. 2476 # (It's only False for __new__, __init__, and METH_STATIC functions.) 2477 show_in_signature = True 2478 2479 # Overrides the name used in a text signature. 2480 # The name used for a "self" parameter must be one of 2481 # self, type, or module; however users can set their own. 2482 # This lets the self_converter overrule the user-settable 2483 # name, *just* for the text signature. 2484 # Only set by self_converter. 2485 signature_name = None 2486 2487 # keep in sync with self_converter.__init__! 2488 def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs): 2489 self.name = ensure_legal_c_identifier(name) 2490 self.py_name = py_name 2491 2492 if default is not unspecified: 2493 if self.default_type and not isinstance(default, (self.default_type, Unknown)): 2494 if isinstance(self.default_type, type): 2495 types_str = self.default_type.__name__ 2496 else: 2497 types_str = ', '.join((cls.__name__ for cls in self.default_type)) 2498 fail("{}: default value {!r} for field {} is not of type {}".format( 2499 self.__class__.__name__, default, name, types_str)) 2500 self.default = default 2501 2502 if c_default: 2503 self.c_default = c_default 2504 if py_default: 2505 self.py_default = py_default 2506 2507 if annotation != unspecified: 2508 fail("The 'annotation' parameter is not currently permitted.") 2509 2510 # this is deliberate, to prevent you from caching information 2511 # about the function in the init. 2512 # (that breaks if we get cloned.) 2513 # so after this change we will noisily fail. 2514 self.function = LandMine("Don't access members of self.function inside converter_init!") 2515 self.converter_init(**kwargs) 2516 self.function = function 2517 2518 def converter_init(self): 2519 pass 2520 2521 def is_optional(self): 2522 return (self.default is not unspecified) 2523 2524 def _render_self(self, parameter, data): 2525 self.parameter = parameter 2526 name = self.name 2527 2528 # impl_arguments 2529 s = ("&" if self.impl_by_reference else "") + name 2530 data.impl_arguments.append(s) 2531 if self.length: 2532 data.impl_arguments.append(self.length_name()) 2533 2534 # impl_parameters 2535 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference)) 2536 if self.length: 2537 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name()) 2538 2539 def _render_non_self(self, parameter, data): 2540 self.parameter = parameter 2541 name = self.name 2542 2543 # declarations 2544 d = self.declaration() 2545 data.declarations.append(d) 2546 2547 # initializers 2548 initializers = self.initialize() 2549 if initializers: 2550 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip()) 2551 2552 # modifications 2553 modifications = self.modify() 2554 if modifications: 2555 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip()) 2556 2557 # keywords 2558 if parameter.is_positional_only(): 2559 data.keywords.append('') 2560 else: 2561 data.keywords.append(parameter.name) 2562 2563 # format_units 2564 if self.is_optional() and '|' not in data.format_units: 2565 data.format_units.append('|') 2566 if parameter.is_keyword_only() and '$' not in data.format_units: 2567 data.format_units.append('$') 2568 data.format_units.append(self.format_unit) 2569 2570 # parse_arguments 2571 self.parse_argument(data.parse_arguments) 2572 2573 # cleanup 2574 cleanup = self.cleanup() 2575 if cleanup: 2576 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") 2577 2578 def render(self, parameter, data): 2579 """ 2580 parameter is a clinic.Parameter instance. 2581 data is a CRenderData instance. 2582 """ 2583 self._render_self(parameter, data) 2584 self._render_non_self(parameter, data) 2585 2586 def length_name(self): 2587 """Computes the name of the associated "length" variable.""" 2588 if not self.length: 2589 return None 2590 return self.name + "_length" 2591 2592 # Why is this one broken out separately? 2593 # For "positional-only" function parsing, 2594 # which generates a bunch of PyArg_ParseTuple calls. 2595 def parse_argument(self, list): 2596 assert not (self.converter and self.encoding) 2597 if self.format_unit == 'O&': 2598 assert self.converter 2599 list.append(self.converter) 2600 2601 if self.encoding: 2602 list.append(c_repr(self.encoding)) 2603 elif self.subclass_of: 2604 list.append(self.subclass_of) 2605 2606 s = ("&" if self.parse_by_reference else "") + self.name 2607 list.append(s) 2608 2609 if self.length: 2610 list.append("&" + self.length_name()) 2611 2612 # 2613 # All the functions after here are intended as extension points. 2614 # 2615 2616 def simple_declaration(self, by_reference=False): 2617 """ 2618 Computes the basic declaration of the variable. 2619 Used in computing the prototype declaration and the 2620 variable declaration. 2621 """ 2622 prototype = [self.type] 2623 if by_reference or not self.type.endswith('*'): 2624 prototype.append(" ") 2625 if by_reference: 2626 prototype.append('*') 2627 prototype.append(self.name) 2628 return "".join(prototype) 2629 2630 def declaration(self): 2631 """ 2632 The C statement to declare this variable. 2633 """ 2634 declaration = [self.simple_declaration()] 2635 default = self.c_default 2636 if not default and self.parameter.group: 2637 default = self.c_ignored_default 2638 if default: 2639 declaration.append(" = ") 2640 declaration.append(default) 2641 declaration.append(";") 2642 if self.length: 2643 declaration.append('\nPy_ssize_clean_t ') 2644 declaration.append(self.length_name()) 2645 declaration.append(';') 2646 return "".join(declaration) 2647 2648 def initialize(self): 2649 """ 2650 The C statements required to set up this variable before parsing. 2651 Returns a string containing this code indented at column 0. 2652 If no initialization is necessary, returns an empty string. 2653 """ 2654 return "" 2655 2656 def modify(self): 2657 """ 2658 The C statements required to modify this variable after parsing. 2659 Returns a string containing this code indented at column 0. 2660 If no initialization is necessary, returns an empty string. 2661 """ 2662 return "" 2663 2664 def cleanup(self): 2665 """ 2666 The C statements required to clean up after this variable. 2667 Returns a string containing this code indented at column 0. 2668 If no cleanup is necessary, returns an empty string. 2669 """ 2670 return "" 2671 2672 def pre_render(self): 2673 """ 2674 A second initialization function, like converter_init, 2675 called just before rendering. 2676 You are permitted to examine self.function here. 2677 """ 2678 pass 2679 2680 def parse_arg(self, argname, displayname): 2681 if self.format_unit == 'O&': 2682 return """ 2683 if (!{converter}({argname}, &{paramname})) {{{{ 2684 goto exit; 2685 }}}} 2686 """.format(argname=argname, paramname=self.name, 2687 converter=self.converter) 2688 if self.format_unit == 'O!': 2689 cast = '(%s)' % self.type if self.type != 'PyObject *' else '' 2690 if self.subclass_of in type_checks: 2691 typecheck, typename = type_checks[self.subclass_of] 2692 return """ 2693 if (!{typecheck}({argname})) {{{{ 2694 _PyArg_BadArgument("{{name}}", {displayname}, "{typename}", {argname}); 2695 goto exit; 2696 }}}} 2697 {paramname} = {cast}{argname}; 2698 """.format(argname=argname, paramname=self.name, 2699 displayname=displayname, typecheck=typecheck, 2700 typename=typename, cast=cast) 2701 return """ 2702 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{ 2703 _PyArg_BadArgument("{{name}}", {displayname}, ({subclass_of})->tp_name, {argname}); 2704 goto exit; 2705 }}}} 2706 {paramname} = {cast}{argname}; 2707 """.format(argname=argname, paramname=self.name, 2708 subclass_of=self.subclass_of, cast=cast, 2709 displayname=displayname) 2710 if self.format_unit == 'O': 2711 cast = '(%s)' % self.type if self.type != 'PyObject *' else '' 2712 return """ 2713 {paramname} = {cast}{argname}; 2714 """.format(argname=argname, paramname=self.name, cast=cast) 2715 return None 2716 2717 def set_template_dict(self, template_dict): 2718 pass 2719 2720 2721type_checks = { 2722 '&PyLong_Type': ('PyLong_Check', 'int'), 2723 '&PyTuple_Type': ('PyTuple_Check', 'tuple'), 2724 '&PyList_Type': ('PyList_Check', 'list'), 2725 '&PySet_Type': ('PySet_Check', 'set'), 2726 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'), 2727 '&PyDict_Type': ('PyDict_Check', 'dict'), 2728 '&PyUnicode_Type': ('PyUnicode_Check', 'str'), 2729 '&PyBytes_Type': ('PyBytes_Check', 'bytes'), 2730 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'), 2731} 2732 2733 2734class bool_converter(CConverter): 2735 type = 'int' 2736 default_type = bool 2737 format_unit = 'p' 2738 c_ignored_default = '0' 2739 2740 def converter_init(self, *, accept={object}): 2741 if accept == {int}: 2742 self.format_unit = 'i' 2743 elif accept != {object}: 2744 fail("bool_converter: illegal 'accept' argument " + repr(accept)) 2745 if self.default is not unspecified: 2746 self.default = bool(self.default) 2747 self.c_default = str(int(self.default)) 2748 2749 def parse_arg(self, argname, displayname): 2750 if self.format_unit == 'i': 2751 # XXX PyFloat_Check can be removed after the end of the 2752 # deprecation in _PyLong_FromNbIndexOrNbInt. 2753 return """ 2754 {paramname} = _PyLong_AsInt({argname}); 2755 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 2756 goto exit; 2757 }}}} 2758 """.format(argname=argname, paramname=self.name) 2759 elif self.format_unit == 'p': 2760 return """ 2761 {paramname} = PyObject_IsTrue({argname}); 2762 if ({paramname} < 0) {{{{ 2763 goto exit; 2764 }}}} 2765 """.format(argname=argname, paramname=self.name) 2766 return super().parse_arg(argname, displayname) 2767 2768class defining_class_converter(CConverter): 2769 """ 2770 A special-case converter: 2771 this is the default converter used for the defining class. 2772 """ 2773 type = 'PyTypeObject *' 2774 format_unit = '' 2775 show_in_signature = False 2776 2777 def converter_init(self, *, type=None): 2778 self.specified_type = type 2779 2780 def render(self, parameter, data): 2781 self._render_self(parameter, data) 2782 2783 def set_template_dict(self, template_dict): 2784 template_dict['defining_class_name'] = self.name 2785 2786 2787class char_converter(CConverter): 2788 type = 'char' 2789 default_type = (bytes, bytearray) 2790 format_unit = 'c' 2791 c_ignored_default = "'\0'" 2792 2793 def converter_init(self): 2794 if isinstance(self.default, self.default_type): 2795 if len(self.default) != 1: 2796 fail("char_converter: illegal default value " + repr(self.default)) 2797 2798 self.c_default = repr(bytes(self.default))[1:] 2799 if self.c_default == '"\'"': 2800 self.c_default = r"'\''" 2801 2802 def parse_arg(self, argname, displayname): 2803 if self.format_unit == 'c': 2804 return """ 2805 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{ 2806 {paramname} = PyBytes_AS_STRING({argname})[0]; 2807 }}}} 2808 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{ 2809 {paramname} = PyByteArray_AS_STRING({argname})[0]; 2810 }}}} 2811 else {{{{ 2812 _PyArg_BadArgument("{{name}}", {displayname}, "a byte string of length 1", {argname}); 2813 goto exit; 2814 }}}} 2815 """.format(argname=argname, paramname=self.name, 2816 displayname=displayname) 2817 return super().parse_arg(argname, displayname) 2818 2819 2820@add_legacy_c_converter('B', bitwise=True) 2821class unsigned_char_converter(CConverter): 2822 type = 'unsigned char' 2823 default_type = int 2824 format_unit = 'b' 2825 c_ignored_default = "'\0'" 2826 2827 def converter_init(self, *, bitwise=False): 2828 if bitwise: 2829 self.format_unit = 'B' 2830 2831 def parse_arg(self, argname, displayname): 2832 if self.format_unit == 'b': 2833 return """ 2834 {{{{ 2835 long ival = PyLong_AsLong({argname}); 2836 if (ival == -1 && PyErr_Occurred()) {{{{ 2837 goto exit; 2838 }}}} 2839 else if (ival < 0) {{{{ 2840 PyErr_SetString(PyExc_OverflowError, 2841 "unsigned byte integer is less than minimum"); 2842 goto exit; 2843 }}}} 2844 else if (ival > UCHAR_MAX) {{{{ 2845 PyErr_SetString(PyExc_OverflowError, 2846 "unsigned byte integer is greater than maximum"); 2847 goto exit; 2848 }}}} 2849 else {{{{ 2850 {paramname} = (unsigned char) ival; 2851 }}}} 2852 }}}} 2853 """.format(argname=argname, paramname=self.name) 2854 elif self.format_unit == 'B': 2855 return """ 2856 {{{{ 2857 unsigned long ival = PyLong_AsUnsignedLongMask({argname}); 2858 if (ival == (unsigned long)-1 && PyErr_Occurred()) {{{{ 2859 goto exit; 2860 }}}} 2861 else {{{{ 2862 {paramname} = (unsigned char) ival; 2863 }}}} 2864 }}}} 2865 """.format(argname=argname, paramname=self.name) 2866 return super().parse_arg(argname, displayname) 2867 2868class byte_converter(unsigned_char_converter): pass 2869 2870class short_converter(CConverter): 2871 type = 'short' 2872 default_type = int 2873 format_unit = 'h' 2874 c_ignored_default = "0" 2875 2876 def parse_arg(self, argname, displayname): 2877 if self.format_unit == 'h': 2878 return """ 2879 {{{{ 2880 long ival = PyLong_AsLong({argname}); 2881 if (ival == -1 && PyErr_Occurred()) {{{{ 2882 goto exit; 2883 }}}} 2884 else if (ival < SHRT_MIN) {{{{ 2885 PyErr_SetString(PyExc_OverflowError, 2886 "signed short integer is less than minimum"); 2887 goto exit; 2888 }}}} 2889 else if (ival > SHRT_MAX) {{{{ 2890 PyErr_SetString(PyExc_OverflowError, 2891 "signed short integer is greater than maximum"); 2892 goto exit; 2893 }}}} 2894 else {{{{ 2895 {paramname} = (short) ival; 2896 }}}} 2897 }}}} 2898 """.format(argname=argname, paramname=self.name) 2899 return super().parse_arg(argname, displayname) 2900 2901class unsigned_short_converter(CConverter): 2902 type = 'unsigned short' 2903 default_type = int 2904 c_ignored_default = "0" 2905 2906 def converter_init(self, *, bitwise=False): 2907 if bitwise: 2908 self.format_unit = 'H' 2909 else: 2910 self.converter = '_PyLong_UnsignedShort_Converter' 2911 2912 def parse_arg(self, argname, displayname): 2913 if self.format_unit == 'H': 2914 return """ 2915 {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname}); 2916 if ({paramname} == (unsigned short)-1 && PyErr_Occurred()) {{{{ 2917 goto exit; 2918 }}}} 2919 """.format(argname=argname, paramname=self.name) 2920 return super().parse_arg(argname, displayname) 2921 2922@add_legacy_c_converter('C', accept={str}) 2923class int_converter(CConverter): 2924 type = 'int' 2925 default_type = int 2926 format_unit = 'i' 2927 c_ignored_default = "0" 2928 2929 def converter_init(self, *, accept={int}, type=None): 2930 if accept == {str}: 2931 self.format_unit = 'C' 2932 elif accept != {int}: 2933 fail("int_converter: illegal 'accept' argument " + repr(accept)) 2934 if type is not None: 2935 self.type = type 2936 2937 def parse_arg(self, argname, displayname): 2938 if self.format_unit == 'i': 2939 return """ 2940 {paramname} = _PyLong_AsInt({argname}); 2941 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 2942 goto exit; 2943 }}}} 2944 """.format(argname=argname, paramname=self.name) 2945 elif self.format_unit == 'C': 2946 return """ 2947 if (!PyUnicode_Check({argname})) {{{{ 2948 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname}); 2949 goto exit; 2950 }}}} 2951 if (PyUnicode_READY({argname})) {{{{ 2952 goto exit; 2953 }}}} 2954 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ 2955 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname}); 2956 goto exit; 2957 }}}} 2958 {paramname} = PyUnicode_READ_CHAR({argname}, 0); 2959 """.format(argname=argname, paramname=self.name, 2960 displayname=displayname) 2961 return super().parse_arg(argname, displayname) 2962 2963class unsigned_int_converter(CConverter): 2964 type = 'unsigned int' 2965 default_type = int 2966 c_ignored_default = "0" 2967 2968 def converter_init(self, *, bitwise=False): 2969 if bitwise: 2970 self.format_unit = 'I' 2971 else: 2972 self.converter = '_PyLong_UnsignedInt_Converter' 2973 2974 def parse_arg(self, argname, displayname): 2975 if self.format_unit == 'I': 2976 return """ 2977 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname}); 2978 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{ 2979 goto exit; 2980 }}}} 2981 """.format(argname=argname, paramname=self.name) 2982 return super().parse_arg(argname, displayname) 2983 2984class long_converter(CConverter): 2985 type = 'long' 2986 default_type = int 2987 format_unit = 'l' 2988 c_ignored_default = "0" 2989 2990 def parse_arg(self, argname, displayname): 2991 if self.format_unit == 'l': 2992 return """ 2993 {paramname} = PyLong_AsLong({argname}); 2994 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 2995 goto exit; 2996 }}}} 2997 """.format(argname=argname, paramname=self.name) 2998 return super().parse_arg(argname, displayname) 2999 3000class unsigned_long_converter(CConverter): 3001 type = 'unsigned long' 3002 default_type = int 3003 c_ignored_default = "0" 3004 3005 def converter_init(self, *, bitwise=False): 3006 if bitwise: 3007 self.format_unit = 'k' 3008 else: 3009 self.converter = '_PyLong_UnsignedLong_Converter' 3010 3011 def parse_arg(self, argname, displayname): 3012 if self.format_unit == 'k': 3013 return """ 3014 if (!PyLong_Check({argname})) {{{{ 3015 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname}); 3016 goto exit; 3017 }}}} 3018 {paramname} = PyLong_AsUnsignedLongMask({argname}); 3019 """.format(argname=argname, paramname=self.name, 3020 displayname=displayname) 3021 return super().parse_arg(argname, displayname) 3022 3023class long_long_converter(CConverter): 3024 type = 'long long' 3025 default_type = int 3026 format_unit = 'L' 3027 c_ignored_default = "0" 3028 3029 def parse_arg(self, argname, displayname): 3030 if self.format_unit == 'L': 3031 return """ 3032 {paramname} = PyLong_AsLongLong({argname}); 3033 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 3034 goto exit; 3035 }}}} 3036 """.format(argname=argname, paramname=self.name) 3037 return super().parse_arg(argname, displayname) 3038 3039class unsigned_long_long_converter(CConverter): 3040 type = 'unsigned long long' 3041 default_type = int 3042 c_ignored_default = "0" 3043 3044 def converter_init(self, *, bitwise=False): 3045 if bitwise: 3046 self.format_unit = 'K' 3047 else: 3048 self.converter = '_PyLong_UnsignedLongLong_Converter' 3049 3050 def parse_arg(self, argname, displayname): 3051 if self.format_unit == 'K': 3052 return """ 3053 if (!PyLong_Check({argname})) {{{{ 3054 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname}); 3055 goto exit; 3056 }}}} 3057 {paramname} = PyLong_AsUnsignedLongLongMask({argname}); 3058 """.format(argname=argname, paramname=self.name, 3059 displayname=displayname) 3060 return super().parse_arg(argname, displayname) 3061 3062class Py_ssize_t_converter(CConverter): 3063 type = 'Py_ssize_t' 3064 c_ignored_default = "0" 3065 3066 def converter_init(self, *, accept={int}): 3067 if accept == {int}: 3068 self.format_unit = 'n' 3069 self.default_type = int 3070 elif accept == {int, NoneType}: 3071 self.converter = '_Py_convert_optional_to_ssize_t' 3072 else: 3073 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept)) 3074 3075 def parse_arg(self, argname, displayname): 3076 if self.format_unit == 'n': 3077 return """ 3078 {{{{ 3079 Py_ssize_t ival = -1; 3080 PyObject *iobj = _PyNumber_Index({argname}); 3081 if (iobj != NULL) {{{{ 3082 ival = PyLong_AsSsize_t(iobj); 3083 Py_DECREF(iobj); 3084 }}}} 3085 if (ival == -1 && PyErr_Occurred()) {{{{ 3086 goto exit; 3087 }}}} 3088 {paramname} = ival; 3089 }}}} 3090 """.format(argname=argname, paramname=self.name) 3091 return super().parse_arg(argname, displayname) 3092 3093 3094class slice_index_converter(CConverter): 3095 type = 'Py_ssize_t' 3096 3097 def converter_init(self, *, accept={int, NoneType}): 3098 if accept == {int}: 3099 self.converter = '_PyEval_SliceIndexNotNone' 3100 elif accept == {int, NoneType}: 3101 self.converter = '_PyEval_SliceIndex' 3102 else: 3103 fail("slice_index_converter: illegal 'accept' argument " + repr(accept)) 3104 3105class size_t_converter(CConverter): 3106 type = 'size_t' 3107 converter = '_PyLong_Size_t_Converter' 3108 c_ignored_default = "0" 3109 3110 def parse_arg(self, argname, displayname): 3111 if self.format_unit == 'n': 3112 return """ 3113 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError); 3114 if ({paramname} == -1 && PyErr_Occurred()) {{{{ 3115 goto exit; 3116 }}}} 3117 """.format(argname=argname, paramname=self.name) 3118 return super().parse_arg(argname, displayname) 3119 3120 3121class fildes_converter(CConverter): 3122 type = 'int' 3123 converter = '_PyLong_FileDescriptor_Converter' 3124 3125 def _parse_arg(self, argname, displayname): 3126 return """ 3127 {paramname} = PyObject_AsFileDescriptor({argname}); 3128 if ({paramname} == -1) {{{{ 3129 goto exit; 3130 }}}} 3131 """.format(argname=argname, paramname=self.name) 3132 3133 3134class float_converter(CConverter): 3135 type = 'float' 3136 default_type = float 3137 format_unit = 'f' 3138 c_ignored_default = "0.0" 3139 3140 def parse_arg(self, argname, displayname): 3141 if self.format_unit == 'f': 3142 return """ 3143 if (PyFloat_CheckExact({argname})) {{{{ 3144 {paramname} = (float) (PyFloat_AS_DOUBLE({argname})); 3145 }}}} 3146 else 3147 {{{{ 3148 {paramname} = (float) PyFloat_AsDouble({argname}); 3149 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{ 3150 goto exit; 3151 }}}} 3152 }}}} 3153 """.format(argname=argname, paramname=self.name) 3154 return super().parse_arg(argname, displayname) 3155 3156class double_converter(CConverter): 3157 type = 'double' 3158 default_type = float 3159 format_unit = 'd' 3160 c_ignored_default = "0.0" 3161 3162 def parse_arg(self, argname, displayname): 3163 if self.format_unit == 'd': 3164 return """ 3165 if (PyFloat_CheckExact({argname})) {{{{ 3166 {paramname} = PyFloat_AS_DOUBLE({argname}); 3167 }}}} 3168 else 3169 {{{{ 3170 {paramname} = PyFloat_AsDouble({argname}); 3171 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{ 3172 goto exit; 3173 }}}} 3174 }}}} 3175 """.format(argname=argname, paramname=self.name) 3176 return super().parse_arg(argname, displayname) 3177 3178 3179class Py_complex_converter(CConverter): 3180 type = 'Py_complex' 3181 default_type = complex 3182 format_unit = 'D' 3183 c_ignored_default = "{0.0, 0.0}" 3184 3185 def parse_arg(self, argname, displayname): 3186 if self.format_unit == 'D': 3187 return """ 3188 {paramname} = PyComplex_AsCComplex({argname}); 3189 if (PyErr_Occurred()) {{{{ 3190 goto exit; 3191 }}}} 3192 """.format(argname=argname, paramname=self.name) 3193 return super().parse_arg(argname, displayname) 3194 3195 3196class object_converter(CConverter): 3197 type = 'PyObject *' 3198 format_unit = 'O' 3199 3200 def converter_init(self, *, converter=None, type=None, subclass_of=None): 3201 if converter: 3202 if subclass_of: 3203 fail("object: Cannot pass in both 'converter' and 'subclass_of'") 3204 self.format_unit = 'O&' 3205 self.converter = converter 3206 elif subclass_of: 3207 self.format_unit = 'O!' 3208 self.subclass_of = subclass_of 3209 3210 if type is not None: 3211 self.type = type 3212 3213 3214# 3215# We define three conventions for buffer types in the 'accept' argument: 3216# 3217# buffer : any object supporting the buffer interface 3218# rwbuffer: any object supporting the buffer interface, but must be writeable 3219# robuffer: any object supporting the buffer interface, but must not be writeable 3220# 3221 3222class buffer: pass 3223class rwbuffer: pass 3224class robuffer: pass 3225 3226def str_converter_key(types, encoding, zeroes): 3227 return (frozenset(types), bool(encoding), bool(zeroes)) 3228 3229str_converter_argument_map = {} 3230 3231class str_converter(CConverter): 3232 type = 'const char *' 3233 default_type = (str, Null, NoneType) 3234 format_unit = 's' 3235 3236 def converter_init(self, *, accept={str}, encoding=None, zeroes=False): 3237 3238 key = str_converter_key(accept, encoding, zeroes) 3239 format_unit = str_converter_argument_map.get(key) 3240 if not format_unit: 3241 fail("str_converter: illegal combination of arguments", key) 3242 3243 self.format_unit = format_unit 3244 self.length = bool(zeroes) 3245 if encoding: 3246 if self.default not in (Null, None, unspecified): 3247 fail("str_converter: Argument Clinic doesn't support default values for encoded strings") 3248 self.encoding = encoding 3249 self.type = 'char *' 3250 # sorry, clinic can't support preallocated buffers 3251 # for es# and et# 3252 self.c_default = "NULL" 3253 if NoneType in accept and self.c_default == "Py_None": 3254 self.c_default = "NULL" 3255 3256 def cleanup(self): 3257 if self.encoding: 3258 name = self.name 3259 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"]) 3260 3261 def parse_arg(self, argname, displayname): 3262 if self.format_unit == 's': 3263 return """ 3264 if (!PyUnicode_Check({argname})) {{{{ 3265 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname}); 3266 goto exit; 3267 }}}} 3268 Py_ssize_t {paramname}_length; 3269 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length); 3270 if ({paramname} == NULL) {{{{ 3271 goto exit; 3272 }}}} 3273 if (strlen({paramname}) != (size_t){paramname}_length) {{{{ 3274 PyErr_SetString(PyExc_ValueError, "embedded null character"); 3275 goto exit; 3276 }}}} 3277 """.format(argname=argname, paramname=self.name, 3278 displayname=displayname) 3279 if self.format_unit == 'z': 3280 return """ 3281 if ({argname} == Py_None) {{{{ 3282 {paramname} = NULL; 3283 }}}} 3284 else if (PyUnicode_Check({argname})) {{{{ 3285 Py_ssize_t {paramname}_length; 3286 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length); 3287 if ({paramname} == NULL) {{{{ 3288 goto exit; 3289 }}}} 3290 if (strlen({paramname}) != (size_t){paramname}_length) {{{{ 3291 PyErr_SetString(PyExc_ValueError, "embedded null character"); 3292 goto exit; 3293 }}}} 3294 }}}} 3295 else {{{{ 3296 _PyArg_BadArgument("{{name}}", {displayname}, "str or None", {argname}); 3297 goto exit; 3298 }}}} 3299 """.format(argname=argname, paramname=self.name, 3300 displayname=displayname) 3301 return super().parse_arg(argname, displayname) 3302 3303# 3304# This is the fourth or fifth rewrite of registering all the 3305# string converter format units. Previous approaches hid 3306# bugs--generally mismatches between the semantics of the format 3307# unit and the arguments necessary to represent those semantics 3308# properly. Hopefully with this approach we'll get it 100% right. 3309# 3310# The r() function (short for "register") both registers the 3311# mapping from arguments to format unit *and* registers the 3312# legacy C converter for that format unit. 3313# 3314def r(format_unit, *, accept, encoding=False, zeroes=False): 3315 if not encoding and format_unit != 's': 3316 # add the legacy c converters here too. 3317 # 3318 # note: add_legacy_c_converter can't work for 3319 # es, es#, et, or et# 3320 # because of their extra encoding argument 3321 # 3322 # also don't add the converter for 's' because 3323 # the metaclass for CConverter adds it for us. 3324 kwargs = {} 3325 if accept != {str}: 3326 kwargs['accept'] = accept 3327 if zeroes: 3328 kwargs['zeroes'] = True 3329 added_f = functools.partial(str_converter, **kwargs) 3330 legacy_converters[format_unit] = added_f 3331 3332 d = str_converter_argument_map 3333 key = str_converter_key(accept, encoding, zeroes) 3334 if key in d: 3335 sys.exit("Duplicate keys specified for str_converter_argument_map!") 3336 d[key] = format_unit 3337 3338r('es', encoding=True, accept={str}) 3339r('es#', encoding=True, zeroes=True, accept={str}) 3340r('et', encoding=True, accept={bytes, bytearray, str}) 3341r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str}) 3342r('s', accept={str}) 3343r('s#', zeroes=True, accept={robuffer, str}) 3344r('y', accept={robuffer}) 3345r('y#', zeroes=True, accept={robuffer}) 3346r('z', accept={str, NoneType}) 3347r('z#', zeroes=True, accept={robuffer, str, NoneType}) 3348del r 3349 3350 3351class PyBytesObject_converter(CConverter): 3352 type = 'PyBytesObject *' 3353 format_unit = 'S' 3354 # accept = {bytes} 3355 3356 def parse_arg(self, argname, displayname): 3357 if self.format_unit == 'S': 3358 return """ 3359 if (!PyBytes_Check({argname})) {{{{ 3360 _PyArg_BadArgument("{{name}}", {displayname}, "bytes", {argname}); 3361 goto exit; 3362 }}}} 3363 {paramname} = ({type}){argname}; 3364 """.format(argname=argname, paramname=self.name, 3365 type=self.type, displayname=displayname) 3366 return super().parse_arg(argname, displayname) 3367 3368class PyByteArrayObject_converter(CConverter): 3369 type = 'PyByteArrayObject *' 3370 format_unit = 'Y' 3371 # accept = {bytearray} 3372 3373 def parse_arg(self, argname, displayname): 3374 if self.format_unit == 'Y': 3375 return """ 3376 if (!PyByteArray_Check({argname})) {{{{ 3377 _PyArg_BadArgument("{{name}}", {displayname}, "bytearray", {argname}); 3378 goto exit; 3379 }}}} 3380 {paramname} = ({type}){argname}; 3381 """.format(argname=argname, paramname=self.name, 3382 type=self.type, displayname=displayname) 3383 return super().parse_arg(argname, displayname) 3384 3385class unicode_converter(CConverter): 3386 type = 'PyObject *' 3387 default_type = (str, Null, NoneType) 3388 format_unit = 'U' 3389 3390 def parse_arg(self, argname, displayname): 3391 if self.format_unit == 'U': 3392 return """ 3393 if (!PyUnicode_Check({argname})) {{{{ 3394 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname}); 3395 goto exit; 3396 }}}} 3397 if (PyUnicode_READY({argname}) == -1) {{{{ 3398 goto exit; 3399 }}}} 3400 {paramname} = {argname}; 3401 """.format(argname=argname, paramname=self.name, 3402 displayname=displayname) 3403 return super().parse_arg(argname, displayname) 3404 3405@add_legacy_c_converter('u') 3406@add_legacy_c_converter('u#', zeroes=True) 3407@add_legacy_c_converter('Z', accept={str, NoneType}) 3408@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True) 3409class Py_UNICODE_converter(CConverter): 3410 type = 'const Py_UNICODE *' 3411 default_type = (str, Null, NoneType) 3412 3413 def converter_init(self, *, accept={str}, zeroes=False): 3414 format_unit = 'Z' if accept=={str, NoneType} else 'u' 3415 if zeroes: 3416 format_unit += '#' 3417 self.length = True 3418 self.format_unit = format_unit 3419 else: 3420 self.accept = accept 3421 if accept == {str}: 3422 self.converter = '_PyUnicode_WideCharString_Converter' 3423 elif accept == {str, NoneType}: 3424 self.converter = '_PyUnicode_WideCharString_Opt_Converter' 3425 else: 3426 fail("Py_UNICODE_converter: illegal 'accept' argument " + repr(accept)) 3427 3428 def cleanup(self): 3429 if not self.length: 3430 return """\ 3431#if !USE_UNICODE_WCHAR_CACHE 3432PyMem_Free((void *){name}); 3433#endif /* USE_UNICODE_WCHAR_CACHE */ 3434""".format(name=self.name) 3435 3436 def parse_arg(self, argname, argnum): 3437 if not self.length: 3438 if self.accept == {str}: 3439 return """ 3440 if (!PyUnicode_Check({argname})) {{{{ 3441 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname}); 3442 goto exit; 3443 }}}} 3444 #if USE_UNICODE_WCHAR_CACHE 3445 {paramname} = _PyUnicode_AsUnicode({argname}); 3446 #else /* USE_UNICODE_WCHAR_CACHE */ 3447 {paramname} = PyUnicode_AsWideCharString({argname}, NULL); 3448 #endif /* USE_UNICODE_WCHAR_CACHE */ 3449 if ({paramname} == NULL) {{{{ 3450 goto exit; 3451 }}}} 3452 """.format(argname=argname, paramname=self.name, argnum=argnum) 3453 elif self.accept == {str, NoneType}: 3454 return """ 3455 if ({argname} == Py_None) {{{{ 3456 {paramname} = NULL; 3457 }}}} 3458 else if (PyUnicode_Check({argname})) {{{{ 3459 #if USE_UNICODE_WCHAR_CACHE 3460 {paramname} = _PyUnicode_AsUnicode({argname}); 3461 #else /* USE_UNICODE_WCHAR_CACHE */ 3462 {paramname} = PyUnicode_AsWideCharString({argname}, NULL); 3463 #endif /* USE_UNICODE_WCHAR_CACHE */ 3464 if ({paramname} == NULL) {{{{ 3465 goto exit; 3466 }}}} 3467 }}}} 3468 else {{{{ 3469 _PyArg_BadArgument("{{name}}", {argnum}, "str or None", {argname}); 3470 goto exit; 3471 }}}} 3472 """.format(argname=argname, paramname=self.name, argnum=argnum) 3473 return super().parse_arg(argname, argnum) 3474 3475@add_legacy_c_converter('s*', accept={str, buffer}) 3476@add_legacy_c_converter('z*', accept={str, buffer, NoneType}) 3477@add_legacy_c_converter('w*', accept={rwbuffer}) 3478class Py_buffer_converter(CConverter): 3479 type = 'Py_buffer' 3480 format_unit = 'y*' 3481 impl_by_reference = True 3482 c_ignored_default = "{NULL, NULL}" 3483 3484 def converter_init(self, *, accept={buffer}): 3485 if self.default not in (unspecified, None): 3486 fail("The only legal default value for Py_buffer is None.") 3487 3488 self.c_default = self.c_ignored_default 3489 3490 if accept == {str, buffer, NoneType}: 3491 format_unit = 'z*' 3492 elif accept == {str, buffer}: 3493 format_unit = 's*' 3494 elif accept == {buffer}: 3495 format_unit = 'y*' 3496 elif accept == {rwbuffer}: 3497 format_unit = 'w*' 3498 else: 3499 fail("Py_buffer_converter: illegal combination of arguments") 3500 3501 self.format_unit = format_unit 3502 3503 def cleanup(self): 3504 name = self.name 3505 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"]) 3506 3507 def parse_arg(self, argname, displayname): 3508 if self.format_unit == 'y*': 3509 return """ 3510 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{ 3511 goto exit; 3512 }}}} 3513 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ 3514 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); 3515 goto exit; 3516 }}}} 3517 """.format(argname=argname, paramname=self.name, 3518 displayname=displayname) 3519 elif self.format_unit == 's*': 3520 return """ 3521 if (PyUnicode_Check({argname})) {{{{ 3522 Py_ssize_t len; 3523 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len); 3524 if (ptr == NULL) {{{{ 3525 goto exit; 3526 }}}} 3527 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0); 3528 }}}} 3529 else {{{{ /* any bytes-like object */ 3530 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{ 3531 goto exit; 3532 }}}} 3533 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ 3534 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); 3535 goto exit; 3536 }}}} 3537 }}}} 3538 """.format(argname=argname, paramname=self.name, 3539 displayname=displayname) 3540 elif self.format_unit == 'w*': 3541 return """ 3542 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{ 3543 PyErr_Clear(); 3544 _PyArg_BadArgument("{{name}}", {displayname}, "read-write bytes-like object", {argname}); 3545 goto exit; 3546 }}}} 3547 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ 3548 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); 3549 goto exit; 3550 }}}} 3551 """.format(argname=argname, paramname=self.name, 3552 displayname=displayname) 3553 return super().parse_arg(argname, displayname) 3554 3555 3556def correct_name_for_self(f): 3557 if f.kind in (CALLABLE, METHOD_INIT): 3558 if f.cls: 3559 return "PyObject *", "self" 3560 return "PyObject *", "module" 3561 if f.kind == STATIC_METHOD: 3562 return "void *", "null" 3563 if f.kind in (CLASS_METHOD, METHOD_NEW): 3564 return "PyTypeObject *", "type" 3565 raise RuntimeError("Unhandled type of function f: " + repr(f.kind)) 3566 3567def required_type_for_self_for_parser(f): 3568 type, _ = correct_name_for_self(f) 3569 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD): 3570 return type 3571 return None 3572 3573 3574class self_converter(CConverter): 3575 """ 3576 A special-case converter: 3577 this is the default converter used for "self". 3578 """ 3579 type = None 3580 format_unit = '' 3581 3582 def converter_init(self, *, type=None): 3583 self.specified_type = type 3584 3585 def pre_render(self): 3586 f = self.function 3587 default_type, default_name = correct_name_for_self(f) 3588 self.signature_name = default_name 3589 self.type = self.specified_type or self.type or default_type 3590 3591 kind = self.function.kind 3592 new_or_init = kind in (METHOD_NEW, METHOD_INIT) 3593 3594 if (kind == STATIC_METHOD) or new_or_init: 3595 self.show_in_signature = False 3596 3597 # tp_new (METHOD_NEW) functions are of type newfunc: 3598 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); 3599 # PyTypeObject is a typedef for struct _typeobject. 3600 # 3601 # tp_init (METHOD_INIT) functions are of type initproc: 3602 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *); 3603 # 3604 # All other functions generated by Argument Clinic are stored in 3605 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction: 3606 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); 3607 # However! We habitually cast these functions to PyCFunction, 3608 # since functions that accept keyword arguments don't fit this signature 3609 # but are stored there anyway. So strict type equality isn't important 3610 # for these functions. 3611 # 3612 # So: 3613 # 3614 # * The name of the first parameter to the impl and the parsing function will always 3615 # be self.name. 3616 # 3617 # * The type of the first parameter to the impl will always be of self.type. 3618 # 3619 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT): 3620 # * The type of the first parameter to the parsing function is also self.type. 3621 # This means that if you step into the parsing function, your "self" parameter 3622 # is of the correct type, which may make debugging more pleasant. 3623 # 3624 # * Else if the function is tp_new (METHOD_NEW): 3625 # * The type of the first parameter to the parsing function is "PyTypeObject *", 3626 # so the type signature of the function call is an exact match. 3627 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type 3628 # in the impl call. 3629 # 3630 # * Else if the function is tp_init (METHOD_INIT): 3631 # * The type of the first parameter to the parsing function is "PyObject *", 3632 # so the type signature of the function call is an exact match. 3633 # * If self.type != "PyObject *", we cast the first parameter to self.type 3634 # in the impl call. 3635 3636 @property 3637 def parser_type(self): 3638 return required_type_for_self_for_parser(self.function) or self.type 3639 3640 def render(self, parameter, data): 3641 """ 3642 parameter is a clinic.Parameter instance. 3643 data is a CRenderData instance. 3644 """ 3645 if self.function.kind == STATIC_METHOD: 3646 return 3647 3648 self._render_self(parameter, data) 3649 3650 if self.type != self.parser_type: 3651 # insert cast to impl_argument[0], aka self. 3652 # we know we're in the first slot in all the CRenderData lists, 3653 # because we render parameters in order, and self is always first. 3654 assert len(data.impl_arguments) == 1 3655 assert data.impl_arguments[0] == self.name 3656 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0] 3657 3658 def set_template_dict(self, template_dict): 3659 template_dict['self_name'] = self.name 3660 template_dict['self_type'] = self.parser_type 3661 kind = self.function.kind 3662 cls = self.function.cls 3663 3664 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef): 3665 type_object = self.function.cls.type_object 3666 if kind == METHOD_NEW: 3667 type_check = '({} == {})'.format(self.name, type_object) 3668 else: 3669 type_check = 'Py_IS_TYPE({}, {})'.format(self.name, type_object) 3670 3671 line = '{} &&\n '.format(type_check) 3672 template_dict['self_type_check'] = line 3673 3674 3675 3676def add_c_return_converter(f, name=None): 3677 if not name: 3678 name = f.__name__ 3679 if not name.endswith('_return_converter'): 3680 return f 3681 name = name[:-len('_return_converter')] 3682 return_converters[name] = f 3683 return f 3684 3685 3686class CReturnConverterAutoRegister(type): 3687 def __init__(cls, name, bases, classdict): 3688 add_c_return_converter(cls) 3689 3690class CReturnConverter(metaclass=CReturnConverterAutoRegister): 3691 3692 # The C type to use for this variable. 3693 # 'type' should be a Python string specifying the type, e.g. "int". 3694 # If this is a pointer type, the type string should end with ' *'. 3695 type = 'PyObject *' 3696 3697 # The Python default value for this parameter, as a Python value. 3698 # Or the magic value "unspecified" if there is no default. 3699 default = None 3700 3701 def __init__(self, *, py_default=None, **kwargs): 3702 self.py_default = py_default 3703 try: 3704 self.return_converter_init(**kwargs) 3705 except TypeError as e: 3706 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items()) 3707 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e)) 3708 3709 def return_converter_init(self): 3710 pass 3711 3712 def declare(self, data, name="_return_value"): 3713 line = [] 3714 add = line.append 3715 add(self.type) 3716 if not self.type.endswith('*'): 3717 add(' ') 3718 add(name + ';') 3719 data.declarations.append(''.join(line)) 3720 data.return_value = name 3721 3722 def err_occurred_if(self, expr, data): 3723 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr)) 3724 3725 def err_occurred_if_null_pointer(self, variable, data): 3726 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable)) 3727 3728 def render(self, function, data): 3729 """ 3730 function is a clinic.Function instance. 3731 data is a CRenderData instance. 3732 """ 3733 pass 3734 3735add_c_return_converter(CReturnConverter, 'object') 3736 3737class NoneType_return_converter(CReturnConverter): 3738 def render(self, function, data): 3739 self.declare(data) 3740 data.return_conversion.append(''' 3741if (_return_value != Py_None) { 3742 goto exit; 3743} 3744return_value = Py_None; 3745Py_INCREF(Py_None); 3746'''.strip()) 3747 3748class bool_return_converter(CReturnConverter): 3749 type = 'int' 3750 3751 def render(self, function, data): 3752 self.declare(data) 3753 self.err_occurred_if("_return_value == -1", data) 3754 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n') 3755 3756class long_return_converter(CReturnConverter): 3757 type = 'long' 3758 conversion_fn = 'PyLong_FromLong' 3759 cast = '' 3760 unsigned_cast = '' 3761 3762 def render(self, function, data): 3763 self.declare(data) 3764 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data) 3765 data.return_conversion.append( 3766 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n'))) 3767 3768class int_return_converter(long_return_converter): 3769 type = 'int' 3770 cast = '(long)' 3771 3772class init_return_converter(long_return_converter): 3773 """ 3774 Special return converter for __init__ functions. 3775 """ 3776 type = 'int' 3777 cast = '(long)' 3778 3779 def render(self, function, data): 3780 pass 3781 3782class unsigned_long_return_converter(long_return_converter): 3783 type = 'unsigned long' 3784 conversion_fn = 'PyLong_FromUnsignedLong' 3785 unsigned_cast = '(unsigned long)' 3786 3787class unsigned_int_return_converter(unsigned_long_return_converter): 3788 type = 'unsigned int' 3789 cast = '(unsigned long)' 3790 unsigned_cast = '(unsigned int)' 3791 3792class Py_ssize_t_return_converter(long_return_converter): 3793 type = 'Py_ssize_t' 3794 conversion_fn = 'PyLong_FromSsize_t' 3795 3796class size_t_return_converter(long_return_converter): 3797 type = 'size_t' 3798 conversion_fn = 'PyLong_FromSize_t' 3799 unsigned_cast = '(size_t)' 3800 3801 3802class double_return_converter(CReturnConverter): 3803 type = 'double' 3804 cast = '' 3805 3806 def render(self, function, data): 3807 self.declare(data) 3808 self.err_occurred_if("_return_value == -1.0", data) 3809 data.return_conversion.append( 3810 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n') 3811 3812class float_return_converter(double_return_converter): 3813 type = 'float' 3814 cast = '(double)' 3815 3816 3817def eval_ast_expr(node, globals, *, filename='-'): 3818 """ 3819 Takes an ast.Expr node. Compiles and evaluates it. 3820 Returns the result of the expression. 3821 3822 globals represents the globals dict the expression 3823 should see. (There's no equivalent for "locals" here.) 3824 """ 3825 3826 if isinstance(node, ast.Expr): 3827 node = node.value 3828 3829 node = ast.Expression(node) 3830 co = compile(node, filename, 'eval') 3831 fn = types.FunctionType(co, globals) 3832 return fn() 3833 3834 3835class IndentStack: 3836 def __init__(self): 3837 self.indents = [] 3838 self.margin = None 3839 3840 def _ensure(self): 3841 if not self.indents: 3842 fail('IndentStack expected indents, but none are defined.') 3843 3844 def measure(self, line): 3845 """ 3846 Returns the length of the line's margin. 3847 """ 3848 if '\t' in line: 3849 fail('Tab characters are illegal in the Argument Clinic DSL.') 3850 stripped = line.lstrip() 3851 if not len(stripped): 3852 # we can't tell anything from an empty line 3853 # so just pretend it's indented like our current indent 3854 self._ensure() 3855 return self.indents[-1] 3856 return len(line) - len(stripped) 3857 3858 def infer(self, line): 3859 """ 3860 Infer what is now the current margin based on this line. 3861 Returns: 3862 1 if we have indented (or this is the first margin) 3863 0 if the margin has not changed 3864 -N if we have dedented N times 3865 """ 3866 indent = self.measure(line) 3867 margin = ' ' * indent 3868 if not self.indents: 3869 self.indents.append(indent) 3870 self.margin = margin 3871 return 1 3872 current = self.indents[-1] 3873 if indent == current: 3874 return 0 3875 if indent > current: 3876 self.indents.append(indent) 3877 self.margin = margin 3878 return 1 3879 # indent < current 3880 if indent not in self.indents: 3881 fail("Illegal outdent.") 3882 outdent_count = 0 3883 while indent != current: 3884 self.indents.pop() 3885 current = self.indents[-1] 3886 outdent_count -= 1 3887 self.margin = margin 3888 return outdent_count 3889 3890 @property 3891 def depth(self): 3892 """ 3893 Returns how many margins are currently defined. 3894 """ 3895 return len(self.indents) 3896 3897 def indent(self, line): 3898 """ 3899 Indents a line by the currently defined margin. 3900 """ 3901 return self.margin + line 3902 3903 def dedent(self, line): 3904 """ 3905 Dedents a line by the currently defined margin. 3906 (The inverse of 'indent'.) 3907 """ 3908 margin = self.margin 3909 indent = self.indents[-1] 3910 if not line.startswith(margin): 3911 fail('Cannot dedent, line does not start with the previous margin:') 3912 return line[indent:] 3913 3914 3915class DSLParser: 3916 def __init__(self, clinic): 3917 self.clinic = clinic 3918 3919 self.directives = {} 3920 for name in dir(self): 3921 # functions that start with directive_ are added to directives 3922 _, s, key = name.partition("directive_") 3923 if s: 3924 self.directives[key] = getattr(self, name) 3925 3926 # functions that start with at_ are too, with an @ in front 3927 _, s, key = name.partition("at_") 3928 if s: 3929 self.directives['@' + key] = getattr(self, name) 3930 3931 self.reset() 3932 3933 def reset(self): 3934 self.function = None 3935 self.state = self.state_dsl_start 3936 self.parameter_indent = None 3937 self.keyword_only = False 3938 self.positional_only = False 3939 self.group = 0 3940 self.parameter_state = self.ps_start 3941 self.seen_positional_with_default = False 3942 self.indent = IndentStack() 3943 self.kind = CALLABLE 3944 self.coexist = False 3945 self.parameter_continuation = '' 3946 self.preserve_output = False 3947 3948 def directive_version(self, required): 3949 global version 3950 if version_comparitor(version, required) < 0: 3951 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required) 3952 3953 def directive_module(self, name): 3954 fields = name.split('.') 3955 new = fields.pop() 3956 module, cls = self.clinic._module_and_class(fields) 3957 if cls: 3958 fail("Can't nest a module inside a class!") 3959 3960 if name in module.classes: 3961 fail("Already defined module " + repr(name) + "!") 3962 3963 m = Module(name, module) 3964 module.modules[name] = m 3965 self.block.signatures.append(m) 3966 3967 def directive_class(self, name, typedef, type_object): 3968 fields = name.split('.') 3969 in_classes = False 3970 parent = self 3971 name = fields.pop() 3972 so_far = [] 3973 module, cls = self.clinic._module_and_class(fields) 3974 3975 parent = cls or module 3976 if name in parent.classes: 3977 fail("Already defined class " + repr(name) + "!") 3978 3979 c = Class(name, module, cls, typedef, type_object) 3980 parent.classes[name] = c 3981 self.block.signatures.append(c) 3982 3983 def directive_set(self, name, value): 3984 if name not in ("line_prefix", "line_suffix"): 3985 fail("unknown variable", repr(name)) 3986 3987 value = value.format_map({ 3988 'block comment start': '/*', 3989 'block comment end': '*/', 3990 }) 3991 3992 self.clinic.__dict__[name] = value 3993 3994 def directive_destination(self, name, command, *args): 3995 if command == 'new': 3996 self.clinic.add_destination(name, *args) 3997 return 3998 3999 if command == 'clear': 4000 self.clinic.get_destination(name).clear() 4001 fail("unknown destination command", repr(command)) 4002 4003 4004 def directive_output(self, command_or_name, destination=''): 4005 fd = self.clinic.destination_buffers 4006 4007 if command_or_name == "preset": 4008 preset = self.clinic.presets.get(destination) 4009 if not preset: 4010 fail("Unknown preset " + repr(destination) + "!") 4011 fd.update(preset) 4012 return 4013 4014 if command_or_name == "push": 4015 self.clinic.destination_buffers_stack.append(fd.copy()) 4016 return 4017 4018 if command_or_name == "pop": 4019 if not self.clinic.destination_buffers_stack: 4020 fail("Can't 'output pop', stack is empty!") 4021 previous_fd = self.clinic.destination_buffers_stack.pop() 4022 fd.update(previous_fd) 4023 return 4024 4025 # secret command for debugging! 4026 if command_or_name == "print": 4027 self.block.output.append(pprint.pformat(fd)) 4028 self.block.output.append('\n') 4029 return 4030 4031 d = self.clinic.get_destination(destination) 4032 4033 if command_or_name == "everything": 4034 for name in list(fd): 4035 fd[name] = d 4036 return 4037 4038 if command_or_name not in fd: 4039 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd)) 4040 fd[command_or_name] = d 4041 4042 def directive_dump(self, name): 4043 self.block.output.append(self.clinic.get_destination(name).dump()) 4044 4045 def directive_print(self, *args): 4046 self.block.output.append(' '.join(args)) 4047 self.block.output.append('\n') 4048 4049 def directive_preserve(self): 4050 if self.preserve_output: 4051 fail("Can't have preserve twice in one block!") 4052 self.preserve_output = True 4053 4054 def at_classmethod(self): 4055 if self.kind is not CALLABLE: 4056 fail("Can't set @classmethod, function is not a normal callable") 4057 self.kind = CLASS_METHOD 4058 4059 def at_staticmethod(self): 4060 if self.kind is not CALLABLE: 4061 fail("Can't set @staticmethod, function is not a normal callable") 4062 self.kind = STATIC_METHOD 4063 4064 def at_coexist(self): 4065 if self.coexist: 4066 fail("Called @coexist twice!") 4067 self.coexist = True 4068 4069 def parse(self, block): 4070 self.reset() 4071 self.block = block 4072 self.saved_output = self.block.output 4073 block.output = [] 4074 block_start = self.clinic.block_parser.line_number 4075 lines = block.input.split('\n') 4076 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number): 4077 if '\t' in line: 4078 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start) 4079 self.state(line) 4080 4081 self.next(self.state_terminal) 4082 self.state(None) 4083 4084 block.output.extend(self.clinic.language.render(clinic, block.signatures)) 4085 4086 if self.preserve_output: 4087 if block.output: 4088 fail("'preserve' only works for blocks that don't produce any output!") 4089 block.output = self.saved_output 4090 4091 @staticmethod 4092 def ignore_line(line): 4093 # ignore comment-only lines 4094 if line.lstrip().startswith('#'): 4095 return True 4096 4097 # Ignore empty lines too 4098 # (but not in docstring sections!) 4099 if not line.strip(): 4100 return True 4101 4102 return False 4103 4104 @staticmethod 4105 def calculate_indent(line): 4106 return len(line) - len(line.strip()) 4107 4108 def next(self, state, line=None): 4109 # real_print(self.state.__name__, "->", state.__name__, ", line=", line) 4110 self.state = state 4111 if line is not None: 4112 self.state(line) 4113 4114 def state_dsl_start(self, line): 4115 # self.block = self.ClinicOutputBlock(self) 4116 if self.ignore_line(line): 4117 return 4118 4119 # is it a directive? 4120 fields = shlex.split(line) 4121 directive_name = fields[0] 4122 directive = self.directives.get(directive_name, None) 4123 if directive: 4124 try: 4125 directive(*fields[1:]) 4126 except TypeError as e: 4127 fail(str(e)) 4128 return 4129 4130 self.next(self.state_modulename_name, line) 4131 4132 def state_modulename_name(self, line): 4133 # looking for declaration, which establishes the leftmost column 4134 # line should be 4135 # modulename.fnname [as c_basename] [-> return annotation] 4136 # square brackets denote optional syntax. 4137 # 4138 # alternatively: 4139 # modulename.fnname [as c_basename] = modulename.existing_fn_name 4140 # clones the parameters and return converter from that 4141 # function. you can't modify them. you must enter a 4142 # new docstring. 4143 # 4144 # (but we might find a directive first!) 4145 # 4146 # this line is permitted to start with whitespace. 4147 # we'll call this number of spaces F (for "function"). 4148 4149 if not line.strip(): 4150 return 4151 4152 self.indent.infer(line) 4153 4154 # are we cloning? 4155 before, equals, existing = line.rpartition('=') 4156 if equals: 4157 full_name, _, c_basename = before.partition(' as ') 4158 full_name = full_name.strip() 4159 c_basename = c_basename.strip() 4160 existing = existing.strip() 4161 if (is_legal_py_identifier(full_name) and 4162 (not c_basename or is_legal_c_identifier(c_basename)) and 4163 is_legal_py_identifier(existing)): 4164 # we're cloning! 4165 fields = [x.strip() for x in existing.split('.')] 4166 function_name = fields.pop() 4167 module, cls = self.clinic._module_and_class(fields) 4168 4169 for existing_function in (cls or module).functions: 4170 if existing_function.name == function_name: 4171 break 4172 else: 4173 existing_function = None 4174 if not existing_function: 4175 print("class", cls, "module", module, "existing", existing) 4176 print("cls. functions", cls.functions) 4177 fail("Couldn't find existing function " + repr(existing) + "!") 4178 4179 fields = [x.strip() for x in full_name.split('.')] 4180 function_name = fields.pop() 4181 module, cls = self.clinic._module_and_class(fields) 4182 4183 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist): 4184 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)") 4185 self.function = existing_function.copy(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, docstring='') 4186 4187 self.block.signatures.append(self.function) 4188 (cls or module).functions.append(self.function) 4189 self.next(self.state_function_docstring) 4190 return 4191 4192 line, _, returns = line.partition('->') 4193 4194 full_name, _, c_basename = line.partition(' as ') 4195 full_name = full_name.strip() 4196 c_basename = c_basename.strip() or None 4197 4198 if not is_legal_py_identifier(full_name): 4199 fail("Illegal function name: {}".format(full_name)) 4200 if c_basename and not is_legal_c_identifier(c_basename): 4201 fail("Illegal C basename: {}".format(c_basename)) 4202 4203 return_converter = None 4204 if returns: 4205 ast_input = "def x() -> {}: pass".format(returns) 4206 module = None 4207 try: 4208 module = ast.parse(ast_input) 4209 except SyntaxError: 4210 pass 4211 if not module: 4212 fail("Badly-formed annotation for " + full_name + ": " + returns) 4213 try: 4214 name, legacy, kwargs = self.parse_converter(module.body[0].returns) 4215 if legacy: 4216 fail("Legacy converter {!r} not allowed as a return converter" 4217 .format(name)) 4218 if name not in return_converters: 4219 fail("No available return converter called " + repr(name)) 4220 return_converter = return_converters[name](**kwargs) 4221 except ValueError: 4222 fail("Badly-formed annotation for " + full_name + ": " + returns) 4223 4224 fields = [x.strip() for x in full_name.split('.')] 4225 function_name = fields.pop() 4226 module, cls = self.clinic._module_and_class(fields) 4227 4228 fields = full_name.split('.') 4229 if fields[-1] in unsupported_special_methods: 4230 fail(f"{fields[-1]} is a special method and cannot be converted to Argument Clinic! (Yet.)") 4231 4232 if fields[-1] == '__new__': 4233 if (self.kind != CLASS_METHOD) or (not cls): 4234 fail("__new__ must be a class method!") 4235 self.kind = METHOD_NEW 4236 elif fields[-1] == '__init__': 4237 if (self.kind != CALLABLE) or (not cls): 4238 fail("__init__ must be a normal method, not a class or static method!") 4239 self.kind = METHOD_INIT 4240 if not return_converter: 4241 return_converter = init_return_converter() 4242 4243 if not return_converter: 4244 return_converter = CReturnConverter() 4245 4246 if not module: 4247 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".") 4248 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, 4249 return_converter=return_converter, kind=self.kind, coexist=self.coexist) 4250 self.block.signatures.append(self.function) 4251 4252 # insert a self converter automatically 4253 type, name = correct_name_for_self(self.function) 4254 kwargs = {} 4255 if cls and type == "PyObject *": 4256 kwargs['type'] = cls.typedef 4257 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs) 4258 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc) 4259 self.function.parameters[sc.name] = p_self 4260 4261 (cls or module).functions.append(self.function) 4262 self.next(self.state_parameters_start) 4263 4264 # Now entering the parameters section. The rules, formally stated: 4265 # 4266 # * All lines must be indented with spaces only. 4267 # * The first line must be a parameter declaration. 4268 # * The first line must be indented. 4269 # * This first line establishes the indent for parameters. 4270 # * We'll call this number of spaces P (for "parameter"). 4271 # * Thenceforth: 4272 # * Lines indented with P spaces specify a parameter. 4273 # * Lines indented with > P spaces are docstrings for the previous 4274 # parameter. 4275 # * We'll call this number of spaces D (for "docstring"). 4276 # * All subsequent lines indented with >= D spaces are stored as 4277 # part of the per-parameter docstring. 4278 # * All lines will have the first D spaces of the indent stripped 4279 # before they are stored. 4280 # * It's illegal to have a line starting with a number of spaces X 4281 # such that P < X < D. 4282 # * A line with < P spaces is the first line of the function 4283 # docstring, which ends processing for parameters and per-parameter 4284 # docstrings. 4285 # * The first line of the function docstring must be at the same 4286 # indent as the function declaration. 4287 # * It's illegal to have any line in the parameters section starting 4288 # with X spaces such that F < X < P. (As before, F is the indent 4289 # of the function declaration.) 4290 # 4291 # Also, currently Argument Clinic places the following restrictions on groups: 4292 # * Each group must contain at least one parameter. 4293 # * Each group may contain at most one group, which must be the furthest 4294 # thing in the group from the required parameters. (The nested group 4295 # must be the first in the group when it's before the required 4296 # parameters, and the last thing in the group when after the required 4297 # parameters.) 4298 # * There may be at most one (top-level) group to the left or right of 4299 # the required parameters. 4300 # * You must specify a slash, and it must be after all parameters. 4301 # (In other words: either all parameters are positional-only, 4302 # or none are.) 4303 # 4304 # Said another way: 4305 # * Each group must contain at least one parameter. 4306 # * All left square brackets before the required parameters must be 4307 # consecutive. (You can't have a left square bracket followed 4308 # by a parameter, then another left square bracket. You can't 4309 # have a left square bracket, a parameter, a right square bracket, 4310 # and then a left square bracket.) 4311 # * All right square brackets after the required parameters must be 4312 # consecutive. 4313 # 4314 # These rules are enforced with a single state variable: 4315 # "parameter_state". (Previously the code was a miasma of ifs and 4316 # separate boolean state variables.) The states are: 4317 # 4318 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line 4319 # 01 2 3 4 5 6 <- state transitions 4320 # 4321 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3. 4322 # 1: ps_left_square_before. left square brackets before required parameters. 4323 # 2: ps_group_before. in a group, before required parameters. 4324 # 3: ps_required. required parameters, positional-or-keyword or positional-only 4325 # (we don't know yet). (renumber left groups!) 4326 # 4: ps_optional. positional-or-keyword or positional-only parameters that 4327 # now must have default values. 4328 # 5: ps_group_after. in a group, after required parameters. 4329 # 6: ps_right_square_after. right square brackets after required parameters. 4330 ps_start, ps_left_square_before, ps_group_before, ps_required, \ 4331 ps_optional, ps_group_after, ps_right_square_after = range(7) 4332 4333 def state_parameters_start(self, line): 4334 if self.ignore_line(line): 4335 return 4336 4337 # if this line is not indented, we have no parameters 4338 if not self.indent.infer(line): 4339 return self.next(self.state_function_docstring, line) 4340 4341 self.parameter_continuation = '' 4342 return self.next(self.state_parameter, line) 4343 4344 4345 def to_required(self): 4346 """ 4347 Transition to the "required" parameter state. 4348 """ 4349 if self.parameter_state != self.ps_required: 4350 self.parameter_state = self.ps_required 4351 for p in self.function.parameters.values(): 4352 p.group = -p.group 4353 4354 def state_parameter(self, line): 4355 if self.parameter_continuation: 4356 line = self.parameter_continuation + ' ' + line.lstrip() 4357 self.parameter_continuation = '' 4358 4359 if self.ignore_line(line): 4360 return 4361 4362 assert self.indent.depth == 2 4363 indent = self.indent.infer(line) 4364 if indent == -1: 4365 # we outdented, must be to definition column 4366 return self.next(self.state_function_docstring, line) 4367 4368 if indent == 1: 4369 # we indented, must be to new parameter docstring column 4370 return self.next(self.state_parameter_docstring_start, line) 4371 4372 line = line.rstrip() 4373 if line.endswith('\\'): 4374 self.parameter_continuation = line[:-1] 4375 return 4376 4377 line = line.lstrip() 4378 4379 if line in ('*', '/', '[', ']'): 4380 self.parse_special_symbol(line) 4381 return 4382 4383 if self.parameter_state in (self.ps_start, self.ps_required): 4384 self.to_required() 4385 elif self.parameter_state == self.ps_left_square_before: 4386 self.parameter_state = self.ps_group_before 4387 elif self.parameter_state == self.ps_group_before: 4388 if not self.group: 4389 self.to_required() 4390 elif self.parameter_state in (self.ps_group_after, self.ps_optional): 4391 pass 4392 else: 4393 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)") 4394 4395 # handle "as" for parameters too 4396 c_name = None 4397 name, have_as_token, trailing = line.partition(' as ') 4398 if have_as_token: 4399 name = name.strip() 4400 if ' ' not in name: 4401 fields = trailing.strip().split(' ') 4402 if not fields: 4403 fail("Invalid 'as' clause!") 4404 c_name = fields[0] 4405 if c_name.endswith(':'): 4406 name += ':' 4407 c_name = c_name[:-1] 4408 fields[0] = name 4409 line = ' '.join(fields) 4410 4411 base, equals, default = line.rpartition('=') 4412 if not equals: 4413 base = default 4414 default = None 4415 4416 module = None 4417 try: 4418 ast_input = "def x({}): pass".format(base) 4419 module = ast.parse(ast_input) 4420 except SyntaxError: 4421 try: 4422 # the last = was probably inside a function call, like 4423 # c: int(accept={str}) 4424 # so assume there was no actual default value. 4425 default = None 4426 ast_input = "def x({}): pass".format(line) 4427 module = ast.parse(ast_input) 4428 except SyntaxError: 4429 pass 4430 if not module: 4431 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line) 4432 4433 function_args = module.body[0].args 4434 4435 if len(function_args.args) > 1: 4436 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line) 4437 if function_args.defaults or function_args.kw_defaults: 4438 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line) 4439 if function_args.vararg or function_args.kwarg: 4440 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line) 4441 4442 parameter = function_args.args[0] 4443 4444 parameter_name = parameter.arg 4445 name, legacy, kwargs = self.parse_converter(parameter.annotation) 4446 4447 if not default: 4448 if self.parameter_state == self.ps_optional: 4449 fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!") 4450 value = unspecified 4451 if 'py_default' in kwargs: 4452 fail("You can't specify py_default without specifying a default value!") 4453 else: 4454 if self.parameter_state == self.ps_required: 4455 self.parameter_state = self.ps_optional 4456 default = default.strip() 4457 bad = False 4458 ast_input = "x = {}".format(default) 4459 bad = False 4460 try: 4461 module = ast.parse(ast_input) 4462 4463 if 'c_default' not in kwargs: 4464 # we can only represent very simple data values in C. 4465 # detect whether default is okay, via a denylist 4466 # of disallowed ast nodes. 4467 class DetectBadNodes(ast.NodeVisitor): 4468 bad = False 4469 def bad_node(self, node): 4470 self.bad = True 4471 4472 # inline function call 4473 visit_Call = bad_node 4474 # inline if statement ("x = 3 if y else z") 4475 visit_IfExp = bad_node 4476 4477 # comprehensions and generator expressions 4478 visit_ListComp = visit_SetComp = bad_node 4479 visit_DictComp = visit_GeneratorExp = bad_node 4480 4481 # literals for advanced types 4482 visit_Dict = visit_Set = bad_node 4483 visit_List = visit_Tuple = bad_node 4484 4485 # "starred": "a = [1, 2, 3]; *a" 4486 visit_Starred = bad_node 4487 4488 denylist = DetectBadNodes() 4489 denylist.visit(module) 4490 bad = denylist.bad 4491 else: 4492 # if they specify a c_default, we can be more lenient about the default value. 4493 # but at least make an attempt at ensuring it's a valid expression. 4494 try: 4495 value = eval(default) 4496 if value == unspecified: 4497 fail("'unspecified' is not a legal default value!") 4498 except NameError: 4499 pass # probably a named constant 4500 except Exception as e: 4501 fail("Malformed expression given as default value\n" 4502 "{!r} caused {!r}".format(default, e)) 4503 if bad: 4504 fail("Unsupported expression as default value: " + repr(default)) 4505 4506 expr = module.body[0].value 4507 # mild hack: explicitly support NULL as a default value 4508 if isinstance(expr, ast.Name) and expr.id == 'NULL': 4509 value = NULL 4510 py_default = '<unrepresentable>' 4511 c_default = "NULL" 4512 elif (isinstance(expr, ast.BinOp) or 4513 (isinstance(expr, ast.UnaryOp) and 4514 not (isinstance(expr.operand, ast.Num) or 4515 (hasattr(ast, 'Constant') and 4516 isinstance(expr.operand, ast.Constant) and 4517 type(expr.operand.value) in (int, float, complex))) 4518 )): 4519 c_default = kwargs.get("c_default") 4520 if not (isinstance(c_default, str) and c_default): 4521 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default." + ast.dump(expr)) 4522 py_default = default 4523 value = unknown 4524 elif isinstance(expr, ast.Attribute): 4525 a = [] 4526 n = expr 4527 while isinstance(n, ast.Attribute): 4528 a.append(n.attr) 4529 n = n.value 4530 if not isinstance(n, ast.Name): 4531 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)") 4532 a.append(n.id) 4533 py_default = ".".join(reversed(a)) 4534 4535 c_default = kwargs.get("c_default") 4536 if not (isinstance(c_default, str) and c_default): 4537 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") 4538 4539 try: 4540 value = eval(py_default) 4541 except NameError: 4542 value = unknown 4543 else: 4544 value = ast.literal_eval(expr) 4545 py_default = repr(value) 4546 if isinstance(value, (bool, None.__class__)): 4547 c_default = "Py_" + py_default 4548 elif isinstance(value, str): 4549 c_default = c_repr(value) 4550 else: 4551 c_default = py_default 4552 4553 except SyntaxError as e: 4554 fail("Syntax error: " + repr(e.text)) 4555 except (ValueError, AttributeError): 4556 value = unknown 4557 c_default = kwargs.get("c_default") 4558 py_default = default 4559 if not (isinstance(c_default, str) and c_default): 4560 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") 4561 4562 kwargs.setdefault('c_default', c_default) 4563 kwargs.setdefault('py_default', py_default) 4564 4565 dict = legacy_converters if legacy else converters 4566 legacy_str = "legacy " if legacy else "" 4567 if name not in dict: 4568 fail('{} is not a valid {}converter'.format(name, legacy_str)) 4569 # if you use a c_name for the parameter, we just give that name to the converter 4570 # but the parameter object gets the python name 4571 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs) 4572 4573 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD 4574 4575 if isinstance(converter, self_converter): 4576 if len(self.function.parameters) == 1: 4577 if (self.parameter_state != self.ps_required): 4578 fail("A 'self' parameter cannot be marked optional.") 4579 if value is not unspecified: 4580 fail("A 'self' parameter cannot have a default value.") 4581 if self.group: 4582 fail("A 'self' parameter cannot be in an optional group.") 4583 kind = inspect.Parameter.POSITIONAL_ONLY 4584 self.parameter_state = self.ps_start 4585 self.function.parameters.clear() 4586 else: 4587 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.") 4588 4589 if isinstance(converter, defining_class_converter): 4590 _lp = len(self.function.parameters) 4591 if _lp == 1: 4592 if (self.parameter_state != self.ps_required): 4593 fail("A 'defining_class' parameter cannot be marked optional.") 4594 if value is not unspecified: 4595 fail("A 'defining_class' parameter cannot have a default value.") 4596 if self.group: 4597 fail("A 'defining_class' parameter cannot be in an optional group.") 4598 else: 4599 fail("A 'defining_class' parameter, if specified, must either be the first thing in the parameter block, or come just after 'self'.") 4600 4601 4602 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group) 4603 4604 if parameter_name in self.function.parameters: 4605 fail("You can't have two parameters named " + repr(parameter_name) + "!") 4606 self.function.parameters[parameter_name] = p 4607 4608 def parse_converter(self, annotation): 4609 if (hasattr(ast, 'Constant') and 4610 isinstance(annotation, ast.Constant) and 4611 type(annotation.value) is str): 4612 return annotation.value, True, {} 4613 4614 if isinstance(annotation, ast.Str): 4615 return annotation.s, True, {} 4616 4617 if isinstance(annotation, ast.Name): 4618 return annotation.id, False, {} 4619 4620 if not isinstance(annotation, ast.Call): 4621 fail("Annotations must be either a name, a function call, or a string.") 4622 4623 name = annotation.func.id 4624 symbols = globals() 4625 4626 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords} 4627 return name, False, kwargs 4628 4629 def parse_special_symbol(self, symbol): 4630 if symbol == '*': 4631 if self.keyword_only: 4632 fail("Function " + self.function.name + " uses '*' more than once.") 4633 self.keyword_only = True 4634 elif symbol == '[': 4635 if self.parameter_state in (self.ps_start, self.ps_left_square_before): 4636 self.parameter_state = self.ps_left_square_before 4637 elif self.parameter_state in (self.ps_required, self.ps_group_after): 4638 self.parameter_state = self.ps_group_after 4639 else: 4640 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") 4641 self.group += 1 4642 self.function.docstring_only = True 4643 elif symbol == ']': 4644 if not self.group: 4645 fail("Function " + self.function.name + " has a ] without a matching [.") 4646 if not any(p.group == self.group for p in self.function.parameters.values()): 4647 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.") 4648 self.group -= 1 4649 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before): 4650 self.parameter_state = self.ps_group_before 4651 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after): 4652 self.parameter_state = self.ps_right_square_after 4653 else: 4654 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)") 4655 elif symbol == '/': 4656 if self.positional_only: 4657 fail("Function " + self.function.name + " uses '/' more than once.") 4658 self.positional_only = True 4659 # ps_required and ps_optional are allowed here, that allows positional-only without option groups 4660 # to work (and have default values!) 4661 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group: 4662 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)") 4663 if self.keyword_only: 4664 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") 4665 # fixup preceding parameters 4666 for p in self.function.parameters.values(): 4667 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)): 4668 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") 4669 p.kind = inspect.Parameter.POSITIONAL_ONLY 4670 4671 def state_parameter_docstring_start(self, line): 4672 self.parameter_docstring_indent = len(self.indent.margin) 4673 assert self.indent.depth == 3 4674 return self.next(self.state_parameter_docstring, line) 4675 4676 # every line of the docstring must start with at least F spaces, 4677 # where F > P. 4678 # these F spaces will be stripped. 4679 def state_parameter_docstring(self, line): 4680 stripped = line.strip() 4681 if stripped.startswith('#'): 4682 return 4683 4684 indent = self.indent.measure(line) 4685 if indent < self.parameter_docstring_indent: 4686 self.indent.infer(line) 4687 assert self.indent.depth < 3 4688 if self.indent.depth == 2: 4689 # back to a parameter 4690 return self.next(self.state_parameter, line) 4691 assert self.indent.depth == 1 4692 return self.next(self.state_function_docstring, line) 4693 4694 assert self.function.parameters 4695 last_parameter = next(reversed(list(self.function.parameters.values()))) 4696 4697 new_docstring = last_parameter.docstring 4698 4699 if new_docstring: 4700 new_docstring += '\n' 4701 if stripped: 4702 new_docstring += self.indent.dedent(line) 4703 4704 last_parameter.docstring = new_docstring 4705 4706 # the final stanza of the DSL is the docstring. 4707 def state_function_docstring(self, line): 4708 if self.group: 4709 fail("Function " + self.function.name + " has a ] without a matching [.") 4710 4711 stripped = line.strip() 4712 if stripped.startswith('#'): 4713 return 4714 4715 new_docstring = self.function.docstring 4716 if new_docstring: 4717 new_docstring += "\n" 4718 if stripped: 4719 line = self.indent.dedent(line).rstrip() 4720 else: 4721 line = '' 4722 new_docstring += line 4723 self.function.docstring = new_docstring 4724 4725 def format_docstring(self): 4726 f = self.function 4727 4728 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 4729 if new_or_init and not f.docstring: 4730 # don't render a docstring at all, no signature, nothing. 4731 return f.docstring 4732 4733 text, add, output = _text_accumulator() 4734 parameters = f.render_parameters 4735 4736 ## 4737 ## docstring first line 4738 ## 4739 4740 if new_or_init: 4741 # classes get *just* the name of the class 4742 # not __new__, not __init__, and not module.classname 4743 assert f.cls 4744 add(f.cls.name) 4745 else: 4746 add(f.name) 4747 add('(') 4748 4749 # populate "right_bracket_count" field for every parameter 4750 assert parameters, "We should always have a self parameter. " + repr(f) 4751 assert isinstance(parameters[0].converter, self_converter) 4752 # self is always positional-only. 4753 assert parameters[0].is_positional_only() 4754 parameters[0].right_bracket_count = 0 4755 positional_only = True 4756 for p in parameters[1:]: 4757 if not p.is_positional_only(): 4758 positional_only = False 4759 else: 4760 assert positional_only 4761 if positional_only: 4762 p.right_bracket_count = abs(p.group) 4763 else: 4764 # don't put any right brackets around non-positional-only parameters, ever. 4765 p.right_bracket_count = 0 4766 4767 right_bracket_count = 0 4768 4769 def fix_right_bracket_count(desired): 4770 nonlocal right_bracket_count 4771 s = '' 4772 while right_bracket_count < desired: 4773 s += '[' 4774 right_bracket_count += 1 4775 while right_bracket_count > desired: 4776 s += ']' 4777 right_bracket_count -= 1 4778 return s 4779 4780 need_slash = False 4781 added_slash = False 4782 need_a_trailing_slash = False 4783 4784 # we only need a trailing slash: 4785 # * if this is not a "docstring_only" signature 4786 # * and if the last *shown* parameter is 4787 # positional only 4788 if not f.docstring_only: 4789 for p in reversed(parameters): 4790 if not p.converter.show_in_signature: 4791 continue 4792 if p.is_positional_only(): 4793 need_a_trailing_slash = True 4794 break 4795 4796 4797 added_star = False 4798 4799 first_parameter = True 4800 last_p = parameters[-1] 4801 line_length = len(''.join(text)) 4802 indent = " " * line_length 4803 def add_parameter(text): 4804 nonlocal line_length 4805 nonlocal first_parameter 4806 if first_parameter: 4807 s = text 4808 first_parameter = False 4809 else: 4810 s = ' ' + text 4811 if line_length + len(s) >= 72: 4812 add('\n') 4813 add(indent) 4814 line_length = len(indent) 4815 s = text 4816 line_length += len(s) 4817 add(s) 4818 4819 for p in parameters: 4820 if not p.converter.show_in_signature: 4821 continue 4822 assert p.name 4823 4824 is_self = isinstance(p.converter, self_converter) 4825 if is_self and f.docstring_only: 4826 # this isn't a real machine-parsable signature, 4827 # so let's not print the "self" parameter 4828 continue 4829 4830 if p.is_positional_only(): 4831 need_slash = not f.docstring_only 4832 elif need_slash and not (added_slash or p.is_positional_only()): 4833 added_slash = True 4834 add_parameter('/,') 4835 4836 if p.is_keyword_only() and not added_star: 4837 added_star = True 4838 add_parameter('*,') 4839 4840 p_add, p_output = text_accumulator() 4841 p_add(fix_right_bracket_count(p.right_bracket_count)) 4842 4843 if isinstance(p.converter, self_converter): 4844 # annotate first parameter as being a "self". 4845 # 4846 # if inspect.Signature gets this function, 4847 # and it's already bound, the self parameter 4848 # will be stripped off. 4849 # 4850 # if it's not bound, it should be marked 4851 # as positional-only. 4852 # 4853 # note: we don't print "self" for __init__, 4854 # because this isn't actually the signature 4855 # for __init__. (it can't be, __init__ doesn't 4856 # have a docstring.) if this is an __init__ 4857 # (or __new__), then this signature is for 4858 # calling the class to construct a new instance. 4859 p_add('$') 4860 4861 name = p.converter.signature_name or p.name 4862 p_add(name) 4863 4864 if p.converter.is_optional(): 4865 p_add('=') 4866 value = p.converter.py_default 4867 if not value: 4868 value = repr(p.converter.default) 4869 p_add(value) 4870 4871 if (p != last_p) or need_a_trailing_slash: 4872 p_add(',') 4873 4874 add_parameter(p_output()) 4875 4876 add(fix_right_bracket_count(0)) 4877 if need_a_trailing_slash: 4878 add_parameter('/') 4879 add(')') 4880 4881 # PEP 8 says: 4882 # 4883 # The Python standard library will not use function annotations 4884 # as that would result in a premature commitment to a particular 4885 # annotation style. Instead, the annotations are left for users 4886 # to discover and experiment with useful annotation styles. 4887 # 4888 # therefore this is commented out: 4889 # 4890 # if f.return_converter.py_default: 4891 # add(' -> ') 4892 # add(f.return_converter.py_default) 4893 4894 if not f.docstring_only: 4895 add("\n" + sig_end_marker + "\n") 4896 4897 docstring_first_line = output() 4898 4899 # now fix up the places where the brackets look wrong 4900 docstring_first_line = docstring_first_line.replace(', ]', ',] ') 4901 4902 # okay. now we're officially building the "parameters" section. 4903 # create substitution text for {parameters} 4904 spacer_line = False 4905 for p in parameters: 4906 if not p.docstring.strip(): 4907 continue 4908 if spacer_line: 4909 add('\n') 4910 else: 4911 spacer_line = True 4912 add(" ") 4913 add(p.name) 4914 add('\n') 4915 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " ")) 4916 parameters = output() 4917 if parameters: 4918 parameters += '\n' 4919 4920 ## 4921 ## docstring body 4922 ## 4923 4924 docstring = f.docstring.rstrip() 4925 lines = [line.rstrip() for line in docstring.split('\n')] 4926 4927 # Enforce the summary line! 4928 # The first line of a docstring should be a summary of the function. 4929 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph 4930 # by itself. 4931 # 4932 # Argument Clinic enforces the following rule: 4933 # * either the docstring is empty, 4934 # * or it must have a summary line. 4935 # 4936 # Guido said Clinic should enforce this: 4937 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html 4938 4939 if len(lines) >= 2: 4940 if lines[1]: 4941 fail("Docstring for " + f.full_name + " does not have a summary line!\n" + 4942 "Every non-blank function docstring must start with\n" + 4943 "a single line summary followed by an empty line.") 4944 elif len(lines) == 1: 4945 # the docstring is only one line right now--the summary line. 4946 # add an empty line after the summary line so we have space 4947 # between it and the {parameters} we're about to add. 4948 lines.append('') 4949 4950 parameters_marker_count = len(docstring.split('{parameters}')) - 1 4951 if parameters_marker_count > 1: 4952 fail('You may not specify {parameters} more than once in a docstring!') 4953 4954 if not parameters_marker_count: 4955 # insert after summary line 4956 lines.insert(2, '{parameters}') 4957 4958 # insert at front of docstring 4959 lines.insert(0, docstring_first_line) 4960 4961 docstring = "\n".join(lines) 4962 4963 add(docstring) 4964 docstring = output() 4965 4966 docstring = linear_format(docstring, parameters=parameters) 4967 docstring = docstring.rstrip() 4968 4969 return docstring 4970 4971 def state_terminal(self, line): 4972 """ 4973 Called when processing the block is done. 4974 """ 4975 assert not line 4976 4977 if not self.function: 4978 return 4979 4980 if self.keyword_only: 4981 values = self.function.parameters.values() 4982 if not values: 4983 no_parameter_after_star = True 4984 else: 4985 last_parameter = next(reversed(list(values))) 4986 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY 4987 if no_parameter_after_star: 4988 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.") 4989 4990 # remove trailing whitespace from all parameter docstrings 4991 for name, value in self.function.parameters.items(): 4992 if not value: 4993 continue 4994 value.docstring = value.docstring.rstrip() 4995 4996 self.function.docstring = self.format_docstring() 4997 4998 4999 5000 5001# maps strings to callables. 5002# the callable should return an object 5003# that implements the clinic parser 5004# interface (__init__ and parse). 5005# 5006# example parsers: 5007# "clinic", handles the Clinic DSL 5008# "python", handles running Python code 5009# 5010parsers = {'clinic' : DSLParser, 'python': PythonParser} 5011 5012 5013clinic = None 5014 5015 5016def main(argv): 5017 import sys 5018 5019 if sys.version_info.major < 3 or sys.version_info.minor < 3: 5020 sys.exit("Error: clinic.py requires Python 3.3 or greater.") 5021 5022 import argparse 5023 cmdline = argparse.ArgumentParser( 5024 description="""Preprocessor for CPython C files. 5025 5026The purpose of the Argument Clinic is automating all the boilerplate involved 5027with writing argument parsing code for builtins and providing introspection 5028signatures ("docstrings") for CPython builtins. 5029 5030For more information see https://docs.python.org/3/howto/clinic.html""") 5031 cmdline.add_argument("-f", "--force", action='store_true') 5032 cmdline.add_argument("-o", "--output", type=str) 5033 cmdline.add_argument("-v", "--verbose", action='store_true') 5034 cmdline.add_argument("--converters", action='store_true') 5035 cmdline.add_argument("--make", action='store_true', 5036 help="Walk --srcdir to run over all relevant files.") 5037 cmdline.add_argument("--srcdir", type=str, default=os.curdir, 5038 help="The directory tree to walk in --make mode.") 5039 cmdline.add_argument("filename", type=str, nargs="*") 5040 ns = cmdline.parse_args(argv) 5041 5042 if ns.converters: 5043 if ns.filename: 5044 print("Usage error: can't specify --converters and a filename at the same time.") 5045 print() 5046 cmdline.print_usage() 5047 sys.exit(-1) 5048 converters = [] 5049 return_converters = [] 5050 ignored = set(""" 5051 add_c_converter 5052 add_c_return_converter 5053 add_default_legacy_c_converter 5054 add_legacy_c_converter 5055 """.strip().split()) 5056 module = globals() 5057 for name in module: 5058 for suffix, ids in ( 5059 ("_return_converter", return_converters), 5060 ("_converter", converters), 5061 ): 5062 if name in ignored: 5063 continue 5064 if name.endswith(suffix): 5065 ids.append((name, name[:-len(suffix)])) 5066 break 5067 print() 5068 5069 print("Legacy converters:") 5070 legacy = sorted(legacy_converters) 5071 print(' ' + ' '.join(c for c in legacy if c[0].isupper())) 5072 print(' ' + ' '.join(c for c in legacy if c[0].islower())) 5073 print() 5074 5075 for title, attribute, ids in ( 5076 ("Converters", 'converter_init', converters), 5077 ("Return converters", 'return_converter_init', return_converters), 5078 ): 5079 print(title + ":") 5080 longest = -1 5081 for name, short_name in ids: 5082 longest = max(longest, len(short_name)) 5083 for name, short_name in sorted(ids, key=lambda x: x[1].lower()): 5084 cls = module[name] 5085 callable = getattr(cls, attribute, None) 5086 if not callable: 5087 continue 5088 signature = inspect.signature(callable) 5089 parameters = [] 5090 for parameter_name, parameter in signature.parameters.items(): 5091 if parameter.kind == inspect.Parameter.KEYWORD_ONLY: 5092 if parameter.default != inspect.Parameter.empty: 5093 s = '{}={!r}'.format(parameter_name, parameter.default) 5094 else: 5095 s = parameter_name 5096 parameters.append(s) 5097 print(' {}({})'.format(short_name, ', '.join(parameters))) 5098 print() 5099 print("All converters also accept (c_default=None, py_default=None, annotation=None).") 5100 print("All return converters also accept (py_default=None).") 5101 sys.exit(0) 5102 5103 if ns.make: 5104 if ns.output or ns.filename: 5105 print("Usage error: can't use -o or filenames with --make.") 5106 print() 5107 cmdline.print_usage() 5108 sys.exit(-1) 5109 if not ns.srcdir: 5110 print("Usage error: --srcdir must not be empty with --make.") 5111 print() 5112 cmdline.print_usage() 5113 sys.exit(-1) 5114 for root, dirs, files in os.walk(ns.srcdir): 5115 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'): 5116 if rcs_dir in dirs: 5117 dirs.remove(rcs_dir) 5118 for filename in files: 5119 if not (filename.endswith('.c') or filename.endswith('.h')): 5120 continue 5121 path = os.path.join(root, filename) 5122 if ns.verbose: 5123 print(path) 5124 parse_file(path, verify=not ns.force) 5125 return 5126 5127 if not ns.filename: 5128 cmdline.print_usage() 5129 sys.exit(-1) 5130 5131 if ns.output and len(ns.filename) > 1: 5132 print("Usage error: can't use -o with multiple filenames.") 5133 print() 5134 cmdline.print_usage() 5135 sys.exit(-1) 5136 5137 for filename in ns.filename: 5138 if ns.verbose: 5139 print(filename) 5140 parse_file(filename, output=ns.output, verify=not ns.force) 5141 5142 5143if __name__ == "__main__": 5144 sys.exit(main(sys.argv[1:])) 5145