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