From 20a6a438bb1b5a0fc8111b5da993f1d14edfb070 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 11 Aug 2025 01:21:50 +0100 Subject: [PATCH 1/8] Begin enforcing docstring length in Argument Clinic --- .../clinic/libclinic/_overlong_docstrings.py | 70 +++++++++++++++++++ Tools/clinic/libclinic/dsl_parser.py | 4 ++ Tools/clinic/libclinic/errors.py | 2 +- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 Tools/clinic/libclinic/_overlong_docstrings.py diff --git a/Tools/clinic/libclinic/_overlong_docstrings.py b/Tools/clinic/libclinic/_overlong_docstrings.py new file mode 100644 index 00000000000000..6c42bbd21116d1 --- /dev/null +++ b/Tools/clinic/libclinic/_overlong_docstrings.py @@ -0,0 +1,70 @@ +OVERLONG_DOCSTRINGS = frozenset(( + '_abc._abc_instancecheck', + '_abc._abc_register', + '_abc._abc_subclasscheck', + '_codecs.lookup', + '_functools.reduce', + '_hashlib.pbkdf2_hmac', + '_io._BufferedIOBase.read1', + '_jit.is_active', + '_jit.is_available', + '_jit.is_enabled', + '_lzma._decode_filter_properties', + '_remote_debugging.RemoteUnwinder.get_async_stack_trace', + '_socket.inet_aton', + '_sre.SRE_Match.expand', + '_sre.SRE_Match.groupdict', + '_sre.SRE_Pattern.finditer', + '_sre.SRE_Pattern.search', + '_sre.SRE_Pattern.sub', + '_sre.SRE_Pattern.subn', + '_ssl._SSLContext.sni_callback', + '_ssl._SSLSocket.pending', + '_ssl.get_default_verify_paths', + '_ssl.RAND_status', + '_sysconfig.config_vars', + '_testcapi.make_exception_with_doc', + '_tkinter.getbusywaitinterval', + '_tkinter.setbusywaitinterval', + 'array.array.buffer_info', + 'array.array.frombytes', + 'array.array.tobytes', + 'bytearray.count', + 'bytearray.find', + 'bytearray.index', + 'bytearray.rfind', + 'bytearray.rindex', + 'bytes.count', + 'bytes.find', + 'bytes.index', + 'bytes.rfind', + 'bytes.rindex', + 'itertools.chain.from_iterable', + 'itertools.combinations_with_replacement.__new__', + 'itertools.cycle.__new__', + 'itertools.starmap.__new__', + 'itertools.takewhile.__new__', + 'math.comb', + 'msvcrt.kbhit', + 'OrderedDict.pop', + 'os.pwritev', + 'os.sched_getaffinity', + 'os.timerfd_gettime', + 'os.timerfd_gettime_ns', + 'pyexpat.xmlparser.ExternalEntityParserCreate', + 'pyexpat.xmlparser.GetReparseDeferralEnabled', + 'pyexpat.xmlparser.UseForeignDTD', + 'str.count', + 'str.find', + 'str.index', + 'str.rfind', + 'str.rindex', + 'str.rsplit', + 'str.split', + 'sys._setprofileallthreads', + 'sys._settraceallthreads', + 'unicodedata.UCD.decomposition', + 'zoneinfo.ZoneInfo.dst', + 'zoneinfo.ZoneInfo.tzname', + 'zoneinfo.ZoneInfo.utcoffset', +)) diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py index eca41531f7c8e9..81a3b1116c93a9 100644 --- a/Tools/clinic/libclinic/dsl_parser.py +++ b/Tools/clinic/libclinic/dsl_parser.py @@ -14,6 +14,7 @@ from libclinic import ( ClinicError, VersionTuple, fail, warn, unspecified, unknown, NULL) +from libclinic._overlong_docstrings import OVERLONG_DOCSTRINGS from libclinic.function import ( Module, Class, Function, Parameter, FunctionKind, @@ -1509,6 +1510,9 @@ def format_docstring(self) -> str: fail(f"Docstring for {f.full_name!r} does not have a summary line!\n" "Every non-blank function docstring must start with " "a single line summary followed by an empty line.") + if len(lines[0]) > 80 and f.full_name not in OVERLONG_DOCSTRINGS: + fail(f"Summary line {f.full_name!r} is too long!\n" + "The summary line must be no longer than 80 characters.") elif len(lines) == 1: # the docstring is only one line right now--the summary line. # add an empty line after the summary line so we have space diff --git a/Tools/clinic/libclinic/errors.py b/Tools/clinic/libclinic/errors.py index f06bdfbd864b2c..0dcdb1045611c2 100644 --- a/Tools/clinic/libclinic/errors.py +++ b/Tools/clinic/libclinic/errors.py @@ -15,7 +15,7 @@ def __post_init__(self) -> None: def report(self, *, warn_only: bool = False) -> str: msg = "Warning" if warn_only else "Error" if self.filename is not None: - msg += f" in file {self.filename!r}" + msg += f" in file '{self.filename}'" if self.lineno is not None: msg += f" on line {self.lineno}" msg += ":\n" From 5803939352a61f2bb7e1a76317c8f569358b844d Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:52:28 +0100 Subject: [PATCH 2/8] Set to 72 chars and check body lines --- .../clinic/libclinic/_overlong_docstrings.py | 401 +++++++++++++++++- Tools/clinic/libclinic/dsl_parser.py | 31 +- 2 files changed, 408 insertions(+), 24 deletions(-) diff --git a/Tools/clinic/libclinic/_overlong_docstrings.py b/Tools/clinic/libclinic/_overlong_docstrings.py index 6c42bbd21116d1..825fb5623d33f4 100644 --- a/Tools/clinic/libclinic/_overlong_docstrings.py +++ b/Tools/clinic/libclinic/_overlong_docstrings.py @@ -1,16 +1,43 @@ -OVERLONG_DOCSTRINGS = frozenset(( +OVERLONG_SUMMARY = frozenset(( + # Modules/ + '_abc._abc_init', '_abc._abc_instancecheck', '_abc._abc_register', '_abc._abc_subclasscheck', + '_asyncio._swap_current_task', '_codecs.lookup', + '_ctypes.byref', + '_curses.assume_default_colors', + '_curses.can_change_color', + '_curses.has_extended_color_support', + '_curses.has_ic', + '_curses.has_key', + '_curses.is_term_resized', + '_curses.mousemask', + '_curses.pair_content', + '_curses.pair_number', + '_curses.putp', + '_curses.reset_prog_mode', + '_curses.reset_shell_mode', + '_curses.start_color', + '_curses.termname', + '_curses.window.enclose', + '_elementtree._set_factories', '_functools.reduce', + '_gdbm.gdbm.setdefault', + '_hashlib.HMAC.hexdigest', + '_hashlib.openssl_shake_128', + '_hashlib.openssl_shake_256', '_hashlib.pbkdf2_hmac', + '_heapq.heappushpop', + '_hmac.HMAC.hexdigest', '_io._BufferedIOBase.read1', - '_jit.is_active', - '_jit.is_available', - '_jit.is_enabled', '_lzma._decode_filter_properties', + '_opcode.has_name', + '_remote_debugging.RemoteUnwinder.__init__', + '_remote_debugging.RemoteUnwinder.get_all_awaited_by', '_remote_debugging.RemoteUnwinder.get_async_stack_trace', + '_socket.if_indextoname', '_socket.inet_aton', '_sre.SRE_Match.expand', '_sre.SRE_Match.groupdict', @@ -20,51 +47,385 @@ '_sre.SRE_Pattern.subn', '_ssl._SSLContext.sni_callback', '_ssl._SSLSocket.pending', + '_ssl._SSLSocket.sendfile', '_ssl.get_default_verify_paths', '_ssl.RAND_status', '_sysconfig.config_vars', '_testcapi.make_exception_with_doc', + '_testcapi.VectorCallClass.set_vectorcall', '_tkinter.getbusywaitinterval', '_tkinter.setbusywaitinterval', + '_tracemalloc.get_traced_memory', + '_tracemalloc.is_tracing', + '_tracemalloc.reset_peak', + '_zstd.get_frame_size', + '_zstd.set_parameter_types', + '_zstd.ZstdDecompressor.decompress', 'array.array.buffer_info', 'array.array.frombytes', + 'array.array.fromfile', 'array.array.tobytes', - 'bytearray.count', - 'bytearray.find', - 'bytearray.index', - 'bytearray.rfind', - 'bytearray.rindex', - 'bytes.count', - 'bytes.find', - 'bytes.index', - 'bytes.rfind', - 'bytes.rindex', + 'cmath.isfinite', + 'datetime.datetime.strptime', + 'gc.freeze', + 'gc.get_objects', + 'itertools.batched.__new__', 'itertools.chain.from_iterable', 'itertools.combinations_with_replacement.__new__', + 'itertools.count.__new__', 'itertools.cycle.__new__', + 'itertools.groupby.__new__', 'itertools.starmap.__new__', 'itertools.takewhile.__new__', 'math.comb', - 'msvcrt.kbhit', - 'OrderedDict.pop', + 'math.isinf', + 'math.nextafter', + 'math.perm', + 'os._exit', + 'os._fcopyfile', + 'os._findfirstfile', + 'os._getdiskusage', + 'os.getresgid', + 'os.getresuid', + 'os.lchmod', + 'os.login_tty', + 'os.lstat', + 'os.posix_fallocate', + 'os.pread', + 'os.preadv', 'os.pwritev', 'os.sched_getaffinity', + 'os.sched_rr_get_interval', 'os.timerfd_gettime', 'os.timerfd_gettime_ns', + 'os.urandom', + 'os.WIFCONTINUED', + 'os.WIFEXITED', + 'os.writev', + 'os.WSTOPSIG', + 'os.WTERMSIG', + 'pwd.getpwall', 'pyexpat.xmlparser.ExternalEntityParserCreate', 'pyexpat.xmlparser.GetReparseDeferralEnabled', + 'pyexpat.xmlparser.SetParamEntityParsing', 'pyexpat.xmlparser.UseForeignDTD', + 'readline.get_history_length', + 'readline.redisplay', + 'readline.set_history_length', + 'signal.set_wakeup_fd', + 'unpack', # struct.unpack + 'unpack_from', # struct.unpack_from + 'termios.tcdrain', + 'unicodedata.UCD.combining', + 'unicodedata.UCD.decomposition', + 'zoneinfo.ZoneInfo.dst', + 'zoneinfo.ZoneInfo.tzname', + 'zoneinfo.ZoneInfo.utcoffset', + + # Objects/ + 'B.zfill', + 'bytearray.count', + 'bytearray.endswith', + 'bytearray.extend', + 'bytearray.find', + 'bytearray.index', + 'bytearray.maketrans', + 'bytearray.rfind', + 'bytearray.rindex', + 'bytearray.rsplit', + 'bytearray.split', + 'bytearray.splitlines', + 'bytearray.startswith', + 'bytes.count', + 'bytes.endswith', + 'bytes.find', + 'bytes.index', + 'bytes.maketrans', + 'bytes.rfind', + 'bytes.rindex', + 'bytes.startswith', + 'code.replace', + 'complex.conjugate', + 'dict.pop', + 'float.as_integer_ratio', + 'frame.f_trace', + 'int.bit_count', + 'OrderedDict.fromkeys', + 'OrderedDict.pop', + 'set.symmetric_difference_update', 'str.count', + 'str.endswith', 'str.find', 'str.index', + 'str.isprintable', 'str.rfind', 'str.rindex', 'str.rsplit', 'str.split', + 'str.startswith', + 'str.strip', + 'str.swapcase', + 'str.zfill', + + # PC/ + 'msvcrt.kbhit', + + # Python/ + 'chr', + 'compile', + 'isinstance', + 'pow', + 'sum', + '_imp._override_multi_interp_extensions_check', + '_imp.find_frozen', + '_jit.is_active', + '_jit.is_available', + '_jit.is_enabled', + 'marshal.dumps', + 'sys._current_exceptions', + 'sys._current_frames', 'sys._setprofileallthreads', 'sys._settraceallthreads', - 'unicodedata.UCD.decomposition', - 'zoneinfo.ZoneInfo.dst', - 'zoneinfo.ZoneInfo.tzname', - 'zoneinfo.ZoneInfo.utcoffset', + 'sys.get_int_max_str_digits', + 'sys.set_int_max_str_digits', +)) + +OVERLONG_BODY = frozenset(( + + # Modules/ + '_abc.get_cache_token', + '_bisect.bisect_left', + '_bisect.bisect_right', + '_bz2.BZ2Decompressor.decompress', + '_codecs.decode', + '_codecs.encode', + '_codecs.lookup_error', + '_codecs.register', + '_codecs.register_error', + '_curses.cbreak', + '_curses.color_content', + '_curses.color_pair', + '_curses.curs_set', + '_curses.def_shell_mode', + '_curses.echo', + '_curses.flash', + '_curses.flushinp', + '_curses.get_escdelay', + '_curses.get_tabsize', + '_curses.init_pair', + '_curses.longname', + '_curses.mouseinterval', + '_curses.mousemask', + '_curses.newwin', + '_curses.nl', + '_curses.nonl', + '_curses.raw', + '_curses.resize_term', + '_curses.resizeterm', + '_curses.set_escdelay', + '_curses.set_tabsize', + '_curses.start_color', + '_curses.tigetnum', + '_curses.tigetstr', + '_curses.use_env', + '_curses.window.border', + '_curses.window.derwin', + '_curses.window.getch', + '_curses.window.getkey', + '_curses.window.inch', + '_curses.window.insch', + '_curses.window.insnstr', + '_curses.window.is_linetouched', + '_curses.window.noutrefresh', + '_curses.window.overlay', + '_curses.window.overwrite', + '_curses.window.refresh', + '_curses.window.scroll', + '_curses.window.subwin', + '_curses.window.touchline', + '_curses_panel.panel.hide', + '_curses_panel.update_panels', + '_functools.reduce', + '_hashlib.get_fips_mode', + '_hashlib.HMAC.hexdigest', + '_heapq.heappushpop_max', + '_hmac.HMAC.hexdigest', + '_io._IOBase.seek', + '_io._TextIOBase.detach', + '_io._WindowsConsoleIO.__init__', + '_io.FileIO.__init__', + '_io.FileIO.read', + '_io.FileIO.readall', + '_io.FileIO.seek', + '_io.open', + '_io.open_code', + '_lzma.LZMADecompressor.decompress', + '_multibytecodec.MultibyteCodec.decode', + '_multibytecodec.MultibyteCodec.encode', + '_posixshmem.shm_unlink', + '_posixsubprocess.fork_exec', + '_remote_debugging.RemoteUnwinder.__init__', + '_remote_debugging.RemoteUnwinder.get_all_awaited_by', + '_remote_debugging.RemoteUnwinder.get_async_stack_trace', + '_remote_debugging.RemoteUnwinder.get_stack_trace', + '_socket.socket.send', + '_sqlite3.Blob.read', + '_sqlite3.Blob.seek', + '_sqlite3.Blob.write', + '_sqlite3.Connection.deserialize', + '_sqlite3.Connection.serialize', + '_sqlite3.Connection.set_progress_handler', + '_sqlite3.Connection.setlimit', + '_ssl._SSLContext.sni_callback', + '_ssl._SSLSocket.context', + '_ssl._SSLSocket.get_channel_binding', + '_ssl._SSLSocket.sendfile', + '_ssl.enum_certificates', + '_ssl.RAND_status', + '_testlimitedcapi.test_long_as_size_t', + '_tkinter.setbusywaitinterval', + '_zstd.ZstdCompressor.__new__', + '_zstd.ZstdCompressor.compress', + '_zstd.ZstdCompressor.flush', + '_zstd.ZstdCompressor.set_pledged_input_size', + '_zstd.ZstdDecompressor.__new__', + '_zstd.ZstdDecompressor.decompress', + '_zstd.ZstdDecompressor.unused_data', + '_zstd.ZstdDict.__new__', + '_zstd.ZstdDict.as_digested_dict', + '_zstd.ZstdDict.as_prefix', + '_zstd.ZstdDict.as_undigested_dict', + 'array.array.byteswap', + 'array.array.fromunicode', + 'array.array.tounicode', + 'binascii.a2b_base64', + 'cmath.isclose', + 'cmath.log', + 'datetime.date.fromtimestamp', + 'datetime.datetime.__new__', + 'datetime.datetime.fromtimestamp', + 'datetime.time.strftime', + 'fcntl.fcntl', + 'fcntl.ioctl', + 'fcntl.lockf', + 'gc.freeze', + 'gc.get_objects', + 'itertools.combinations_with_replacement.__new__', + 'itertools.compress.__new__', + 'math.nextafter', + 'os.abort', + 'os.access', + 'os.chdir', + 'os.chflags', + 'os.chown', + 'os.fspath', + 'os.getppid', + 'os.getxattr', + 'os.initgroups', + 'os.lchmod', + 'os.link', + 'os.listdir', + 'os.listxattr', + 'os.lseek', + 'os.mkdir', + 'os.mkfifo', + 'os.mknod', + 'os.open', + 'os.pathconf', + 'os.pidfd_open', + 'os.posix_fadvise', + 'os.posix_fallocate', + 'os.posix_openpt', + 'os.preadv', + 'os.pwritev', + 'os.readinto', + 'os.readlink', + 'os.remove', + 'os.removexattr', + 'os.rename', + 'os.replace', + 'os.rmdir', + 'os.scandir', + 'os.setxattr', + 'os.statvfs', + 'os.symlink', + 'os.truncate', + 'os.unlink', + 'os.utime', + 'os.waitid', + 'os.waitstatus_to_exitcode', + 'pyexpat.xmlparser.GetInputContext', + 'pyexpat.xmlparser.UseForeignDTD', + 'select.devpoll', + 'select.poll', + 'select.select', + 'signal.setitimer', + 'signal.signal', + 'signal.sigtimedwait', + 'signal.sigwait', + 'Struct.__init__', + 'termios.tcsetwinsize', + 'zlib.Decompress.decompress', + 'zlib.ZlibDecompressor.decompress', + + # Objects/ + 'bytearray.maketrans', + 'bytearray.partition', + 'bytearray.replace', + 'bytearray.rpartition', + 'bytearray.rsplit', + 'bytearray.splitlines', + 'bytearray.strip', + 'bytes.maketrans', + 'bytes.partition', + 'bytes.replace', + 'bytes.rpartition', + 'bytes.rsplit', + 'bytes.splitlines', + 'bytes.strip', + 'float.__getformat__', + 'list.sort', + 'memoryview.tobytes', + 'str.capitalize', + 'str.isalnum', + 'str.isalpha', + 'str.isdecimal', + 'str.isdigit', + 'str.isidentifier', + 'str.islower', + 'str.isnumeric', + 'str.isspace', + 'str.isupper', + 'str.join', + 'str.partition', + 'str.removeprefix', + 'str.replace', + 'str.rpartition', + 'str.splitlines', + 'str.title', + 'str.translate', + + # PC/ + '_wmi.exec_query', + + # Python/ + '__import__', + 'compile', + 'globals', + 'hash', + 'input', + 'isinstance', + 'issubclass', + 'locals', + 'pow', + 'round', + 'sum', + '_contextvars.ContextVar.get', + '_contextvars.ContextVar.reset', + '_contextvars.ContextVar.set', + '_imp.acquire_lock', + 'marshal.dumps', + 'marshal.loads', + 'sys._stats_dump', + 'sys.remote_exec', )) diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py index 81a3b1116c93a9..6d2c084c3a7d49 100644 --- a/Tools/clinic/libclinic/dsl_parser.py +++ b/Tools/clinic/libclinic/dsl_parser.py @@ -14,7 +14,7 @@ from libclinic import ( ClinicError, VersionTuple, fail, warn, unspecified, unknown, NULL) -from libclinic._overlong_docstrings import OVERLONG_DOCSTRINGS +from libclinic._overlong_docstrings import OVERLONG_SUMMARY, OVERLONG_BODY from libclinic.function import ( Module, Class, Function, Parameter, FunctionKind, @@ -1510,15 +1510,38 @@ def format_docstring(self) -> str: fail(f"Docstring for {f.full_name!r} does not have a summary line!\n" "Every non-blank function docstring must start with " "a single line summary followed by an empty line.") - if len(lines[0]) > 80 and f.full_name not in OVERLONG_DOCSTRINGS: - fail(f"Summary line {f.full_name!r} is too long!\n" - "The summary line must be no longer than 80 characters.") elif len(lines) == 1: # the docstring is only one line right now--the summary line. # add an empty line after the summary line so we have space # between it and the {parameters} we're about to add. lines.append('') + # PEP 8 requires that docstrings are limited to 72 characters: + # + # The Python standard library is conservative and requires + # limiting lines to 79 characters (and docstrings to 72). + # + # Fail if the summary line is too long. + # Warn if any of the body lines are too long. + # Existing violations are recorded in OVERLONG_{SUMMARY,BODY}. + summary_len = len(lines[0]) + max_body = max(map(len, lines[1:])) + if summary_len > 72: + if f.full_name not in OVERLONG_SUMMARY: + fail(f"Summary line for {f.full_name!r} is too long!\n" + f"The summary line must be no longer than 72 characters.") + else: + if f.full_name in OVERLONG_SUMMARY: + fail(f"Remove {f.full_name!r} from OVERLONG_SUMMARY!\n") + + if max_body > 72: + if f.full_name not in OVERLONG_BODY: + warn(f"Docstring lines for {f.full_name!r} are too long!\n" + f"Lines should be no longer than 72 characters.") + else: + if f.full_name in OVERLONG_BODY: + fail(f"Remove {f.full_name!r} from OVERLONG_BODY!\n") + parameters_marker_count = len(f.docstring.split('{parameters}')) - 1 if parameters_marker_count > 1: fail('You may not specify {parameters} more than once in a docstring!') From 48b617b4694971e607571df67213ea2161270318 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 12 Aug 2025 01:26:44 +0100 Subject: [PATCH 3/8] Fix tests --- Lib/test/clinic.test.c | 20 +++++++++++++------ Modules/clinic/posixmodule.c.h | 6 +++--- Modules/posixmodule.c | 6 +++--- .../clinic/libclinic/_overlong_docstrings.py | 4 +++- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index dc5b4b27a07f99..b0f7e402469ffc 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -5084,14 +5084,18 @@ Test_an_metho_arg_named_arg_impl(TestObj *self, int arg) Test.__init__ *args: tuple -Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE. +Varargs init method. + +For example, nargs is translated to PyTuple_GET_SIZE. [clinic start generated code]*/ PyDoc_STRVAR(Test___init____doc__, "Test(*args)\n" "--\n" "\n" -"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE."); +"Varargs init method.\n" +"\n" +"For example, nargs is translated to PyTuple_GET_SIZE."); static int Test___init___impl(TestObj *self, PyObject *args); @@ -5120,21 +5124,25 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) static int Test___init___impl(TestObj *self, PyObject *args) -/*[clinic end generated code: output=f172425cec373cd6 input=4b8388c4e6baab6f]*/ +/*[clinic end generated code: output=0e5836c40dbc2397 input=a615a4485c0fc3e2]*/ /*[clinic input] @classmethod Test.__new__ *args: tuple -Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE. +Varargs new method. + +For example, nargs is translated to PyTuple_GET_SIZE. [clinic start generated code]*/ PyDoc_STRVAR(Test__doc__, "Test(*args)\n" "--\n" "\n" -"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE."); +"Varargs new method.\n" +"\n" +"For example, nargs is translated to PyTuple_GET_SIZE."); static PyObject * Test_impl(PyTypeObject *type, PyObject *args); @@ -5162,7 +5170,7 @@ Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) static PyObject * Test_impl(PyTypeObject *type, PyObject *args) -/*[clinic end generated code: output=ee1e8892a67abd4a input=a8259521129cad20]*/ +/*[clinic end generated code: output=e6fba0c8951882fd input=8ce30adb836aeacb]*/ /*[clinic input] diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 8af9e1db781c8f..df4f802ff0bdc9 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -215,8 +215,8 @@ PyDoc_STRVAR(os_access__doc__, " NotImplementedError.\n" "\n" "Note that most operations will use the effective uid/gid, therefore this\n" -" routine can be used in a suid/sgid environment to test if the invoking user\n" -" has the specified access to the path."); +" routine can be used in a suid/sgid environment to test if the invoking\n" +" user has the specified access to the path."); #define OS_ACCESS_METHODDEF \ {"access", _PyCFunction_CAST(os_access), METH_FASTCALL|METH_KEYWORDS, os_access__doc__}, @@ -13419,4 +13419,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=b1e2615384347102 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=23de5d098e2dd73f input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b1a80788bd8115..76dbb84691db1f 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3295,15 +3295,15 @@ dir_fd, effective_ids, and follow_symlinks may not be implemented NotImplementedError. Note that most operations will use the effective uid/gid, therefore this - routine can be used in a suid/sgid environment to test if the invoking user - has the specified access to the path. + routine can be used in a suid/sgid environment to test if the invoking + user has the specified access to the path. [clinic start generated code]*/ static int os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) -/*[clinic end generated code: output=cf84158bc90b1a77 input=3ffe4e650ee3bf20]*/ +/*[clinic end generated code: output=cf84158bc90b1a77 input=c33565f7584b99e4]*/ { int return_value; diff --git a/Tools/clinic/libclinic/_overlong_docstrings.py b/Tools/clinic/libclinic/_overlong_docstrings.py index 825fb5623d33f4..44271e5f5df015 100644 --- a/Tools/clinic/libclinic/_overlong_docstrings.py +++ b/Tools/clinic/libclinic/_overlong_docstrings.py @@ -1,4 +1,7 @@ OVERLONG_SUMMARY = frozenset(( + # Lib/test/ + 'test_preprocessor_guarded_if_e_or_f', + # Modules/ '_abc._abc_init', '_abc._abc_instancecheck', @@ -314,7 +317,6 @@ 'itertools.compress.__new__', 'math.nextafter', 'os.abort', - 'os.access', 'os.chdir', 'os.chflags', 'os.chown', From cac98910add3413c7d401636a96f9a24996f6182 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 12 Aug 2025 19:39:15 +0100 Subject: [PATCH 4/8] Use 68 characters for methods --- .../clinic/libclinic/_overlong_docstrings.py | 93 ++++++++++++++++++- Tools/clinic/libclinic/dsl_parser.py | 18 ++-- Tools/clinic/libclinic/function.py | 13 +++ 3 files changed, 112 insertions(+), 12 deletions(-) diff --git a/Tools/clinic/libclinic/_overlong_docstrings.py b/Tools/clinic/libclinic/_overlong_docstrings.py index 44271e5f5df015..348c8f732aa8d1 100644 --- a/Tools/clinic/libclinic/_overlong_docstrings.py +++ b/Tools/clinic/libclinic/_overlong_docstrings.py @@ -9,6 +9,7 @@ '_abc._abc_subclasscheck', '_asyncio._swap_current_task', '_codecs.lookup', + '_collections.deque.rotate', '_ctypes.byref', '_curses.assume_default_colors', '_curses.can_change_color', @@ -25,6 +26,8 @@ '_curses.start_color', '_curses.termname', '_curses.window.enclose', + '_curses.window.is_linetouched', + '_curses.window.putwin', '_elementtree._set_factories', '_functools.reduce', '_gdbm.gdbm.setdefault', @@ -35,6 +38,7 @@ '_heapq.heappushpop', '_hmac.HMAC.hexdigest', '_io._BufferedIOBase.read1', + '_io.FileIO.truncate', '_lzma._decode_filter_properties', '_opcode.has_name', '_remote_debugging.RemoteUnwinder.__init__', @@ -42,8 +46,10 @@ '_remote_debugging.RemoteUnwinder.get_async_stack_trace', '_socket.if_indextoname', '_socket.inet_aton', + '_sqlite3.Connection.set_trace_callback', '_sre.SRE_Match.expand', '_sre.SRE_Match.groupdict', + '_sre.SRE_Match.span', '_sre.SRE_Pattern.finditer', '_sre.SRE_Pattern.search', '_sre.SRE_Pattern.sub', @@ -63,13 +69,16 @@ '_tracemalloc.reset_peak', '_zstd.get_frame_size', '_zstd.set_parameter_types', + '_zstd.ZstdCompressor.set_pledged_input_size', '_zstd.ZstdDecompressor.decompress', 'array.array.buffer_info', 'array.array.frombytes', 'array.array.fromfile', 'array.array.tobytes', 'cmath.isfinite', + 'datetime.date.strptime', 'datetime.datetime.strptime', + 'datetime.time.strptime', 'gc.freeze', 'gc.get_objects', 'itertools.batched.__new__', @@ -109,18 +118,27 @@ 'os.WTERMSIG', 'pwd.getpwall', 'pyexpat.xmlparser.ExternalEntityParserCreate', + 'pyexpat.xmlparser.GetInputContext', 'pyexpat.xmlparser.GetReparseDeferralEnabled', 'pyexpat.xmlparser.SetParamEntityParsing', + 'pyexpat.xmlparser.SetReparseDeferralEnabled', 'pyexpat.xmlparser.UseForeignDTD', 'readline.get_history_length', 'readline.redisplay', 'readline.set_history_length', + 'select.epoll.register', 'signal.set_wakeup_fd', 'unpack', # struct.unpack 'unpack_from', # struct.unpack_from 'termios.tcdrain', + 'unicodedata.UCD.bidirectional', + 'unicodedata.UCD.category', 'unicodedata.UCD.combining', 'unicodedata.UCD.decomposition', + 'unicodedata.UCD.east_asian_width', + 'unicodedata.UCD.is_normalized', + 'unicodedata.UCD.mirrored', + 'zlib.Decompress.decompress', 'zoneinfo.ZoneInfo.dst', 'zoneinfo.ZoneInfo.tzname', 'zoneinfo.ZoneInfo.utcoffset', @@ -139,35 +157,53 @@ 'bytearray.split', 'bytearray.splitlines', 'bytearray.startswith', + 'bytearray.translate', 'bytes.count', 'bytes.endswith', 'bytes.find', 'bytes.index', 'bytes.maketrans', + 'bytes.removeprefix', + 'bytes.removesuffix', 'bytes.rfind', 'bytes.rindex', + 'bytes.rsplit', + 'bytes.split', + 'bytes.splitlines', 'bytes.startswith', + 'bytes.translate', 'code.replace', 'complex.conjugate', + 'dict.fromkeys', 'dict.pop', 'float.as_integer_ratio', + 'frame.f_generator', 'frame.f_trace', 'int.bit_count', + 'int.is_integer', 'OrderedDict.fromkeys', 'OrderedDict.pop', + 'set.difference', + 'set.symmetric_difference', 'set.symmetric_difference_update', + 'str.__format__', 'str.count', 'str.endswith', 'str.find', 'str.index', + 'str.isalnum', + 'str.isascii', + 'str.isidentifier', 'str.isprintable', 'str.rfind', 'str.rindex', 'str.rsplit', 'str.split', + 'str.splitlines', 'str.startswith', 'str.strip', 'str.swapcase', + 'str.translate', 'str.zfill', # PC/ @@ -179,6 +215,8 @@ 'isinstance', 'pow', 'sum', + '_contextvars.Context.get', + '_contextvars.ContextVar.set', '_imp._override_multi_interp_extensions_check', '_imp.find_frozen', '_jit.is_active', @@ -197,6 +235,10 @@ # Modules/ '_abc.get_cache_token', + '_asyncio.Future.add_done_callback', + '_asyncio.Future.cancel', + '_asyncio.Future.done', + '_asyncio.Future.result', '_bisect.bisect_left', '_bisect.bisect_right', '_bz2.BZ2Decompressor.decompress', @@ -232,12 +274,14 @@ '_curses.tigetstr', '_curses.use_env', '_curses.window.border', + '_curses.window.box', '_curses.window.derwin', '_curses.window.getch', '_curses.window.getkey', '_curses.window.inch', '_curses.window.insch', '_curses.window.insnstr', + '_curses.window.insstr', '_curses.window.is_linetouched', '_curses.window.noutrefresh', '_curses.window.overlay', @@ -248,37 +292,57 @@ '_curses.window.touchline', '_curses_panel.panel.hide', '_curses_panel.update_panels', + '_dbm.dbm.setdefault', '_functools.reduce', + '_gdbm.gdbm.firstkey', + '_gdbm.gdbm.nextkey', + '_gdbm.gdbm.reorganize', '_hashlib.get_fips_mode', '_hashlib.HMAC.hexdigest', '_heapq.heappushpop_max', '_hmac.HMAC.hexdigest', '_io._IOBase.seek', + '_io._IOBase.truncate', '_io._TextIOBase.detach', + '_io._TextIOBase.read', '_io._WindowsConsoleIO.__init__', + '_io.BytesIO.read1', + '_io.BytesIO.writelines', '_io.FileIO.__init__', + '_io.FileIO.close', '_io.FileIO.read', '_io.FileIO.readall', '_io.FileIO.seek', + '_io.FileIO.write', '_io.open', '_io.open_code', + '_io.StringIO.seek', + '_io.TextIOWrapper.tell', '_lzma.LZMADecompressor.decompress', '_multibytecodec.MultibyteCodec.decode', '_multibytecodec.MultibyteCodec.encode', + '_overlapped.Overlapped.getresult', '_posixshmem.shm_unlink', '_posixsubprocess.fork_exec', + '_queue.SimpleQueue.get', + '_queue.SimpleQueue.put', '_remote_debugging.RemoteUnwinder.__init__', '_remote_debugging.RemoteUnwinder.get_all_awaited_by', '_remote_debugging.RemoteUnwinder.get_async_stack_trace', '_remote_debugging.RemoteUnwinder.get_stack_trace', '_socket.socket.send', + '_socket.socket.sendall', + '_socket.socket.sendmsg', '_sqlite3.Blob.read', '_sqlite3.Blob.seek', '_sqlite3.Blob.write', + '_sqlite3.Connection.__exit__', '_sqlite3.Connection.deserialize', '_sqlite3.Connection.serialize', '_sqlite3.Connection.set_progress_handler', '_sqlite3.Connection.setlimit', + '_ssl._SSLContext.cert_store_stats', + '_ssl._SSLContext.get_ca_certs', '_ssl._SSLContext.sni_callback', '_ssl._SSLSocket.context', '_ssl._SSLSocket.get_channel_binding', @@ -286,6 +350,7 @@ '_ssl.enum_certificates', '_ssl.RAND_status', '_testlimitedcapi.test_long_as_size_t', + '_testmultiphase.StateAccessType.get_defining_module', '_tkinter.setbusywaitinterval', '_zstd.ZstdCompressor.__new__', '_zstd.ZstdCompressor.compress', @@ -298,6 +363,7 @@ '_zstd.ZstdDict.as_digested_dict', '_zstd.ZstdDict.as_prefix', '_zstd.ZstdDict.as_undigested_dict', + 'array.array.buffer_info', 'array.array.byteswap', 'array.array.fromunicode', 'array.array.tounicode', @@ -307,6 +373,7 @@ 'datetime.date.fromtimestamp', 'datetime.datetime.__new__', 'datetime.datetime.fromtimestamp', + 'datetime.time.isoformat', 'datetime.time.strftime', 'fcntl.fcntl', 'fcntl.ioctl', @@ -359,18 +426,24 @@ 'pyexpat.xmlparser.GetInputContext', 'pyexpat.xmlparser.UseForeignDTD', 'select.devpoll', + 'select.devpoll.poll', + 'select.epoll.poll', 'select.poll', + 'select.poll.poll', 'select.select', 'signal.setitimer', 'signal.signal', 'signal.sigtimedwait', 'signal.sigwait', - 'Struct.__init__', + 'Struct.__init__', # struct.Struct.__init__ + 'Struct.unpack', # struct.Struct.unpack 'termios.tcsetwinsize', 'zlib.Decompress.decompress', 'zlib.ZlibDecompressor.decompress', # Objects/ + 'bytearray.fromhex', + 'bytearray.join', 'bytearray.maketrans', 'bytearray.partition', 'bytearray.replace', @@ -378,17 +451,27 @@ 'bytearray.rsplit', 'bytearray.splitlines', 'bytearray.strip', + 'bytearray.translate', 'bytes.maketrans', 'bytes.partition', + 'bytes.removeprefix', + 'bytes.removesuffix', 'bytes.replace', 'bytes.rpartition', 'bytes.rsplit', 'bytes.splitlines', 'bytes.strip', + 'bytes.translate', + 'code._varname_from_oparg', 'float.__getformat__', 'list.sort', 'memoryview.tobytes', + 'OrderedDict.popitem', 'str.capitalize', + 'str.center', + 'str.count', + 'str.find', + 'str.index', 'str.isalnum', 'str.isalpha', 'str.isdecimal', @@ -399,10 +482,17 @@ 'str.isspace', 'str.isupper', 'str.join', + 'str.ljust', + 'str.maketrans', 'str.partition', 'str.removeprefix', + 'str.removesuffix', 'str.replace', + 'str.rfind', + 'str.rindex', + 'str.rjust', 'str.rpartition', + 'str.split', 'str.splitlines', 'str.title', 'str.translate', @@ -422,6 +512,7 @@ 'pow', 'round', 'sum', + '_contextvars.Context.get', '_contextvars.ContextVar.get', '_contextvars.ContextVar.reset', '_contextvars.ContextVar.set', diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py index 6d2c084c3a7d49..58430df6173fd0 100644 --- a/Tools/clinic/libclinic/dsl_parser.py +++ b/Tools/clinic/libclinic/dsl_parser.py @@ -1516,31 +1516,27 @@ def format_docstring(self) -> str: # between it and the {parameters} we're about to add. lines.append('') - # PEP 8 requires that docstrings are limited to 72 characters: - # - # The Python standard library is conservative and requires - # limiting lines to 79 characters (and docstrings to 72). - # # Fail if the summary line is too long. # Warn if any of the body lines are too long. # Existing violations are recorded in OVERLONG_{SUMMARY,BODY}. + max_width = f.docstring_line_width summary_len = len(lines[0]) max_body = max(map(len, lines[1:])) - if summary_len > 72: + if summary_len > max_width: if f.full_name not in OVERLONG_SUMMARY: fail(f"Summary line for {f.full_name!r} is too long!\n" - f"The summary line must be no longer than 72 characters.") + f"The summary line must be no longer than {max_width} characters.") else: if f.full_name in OVERLONG_SUMMARY: - fail(f"Remove {f.full_name!r} from OVERLONG_SUMMARY!\n") + warn(f"Remove {f.full_name!r} from OVERLONG_SUMMARY!\n") - if max_body > 72: + if max_body > max_width: if f.full_name not in OVERLONG_BODY: warn(f"Docstring lines for {f.full_name!r} are too long!\n" - f"Lines should be no longer than 72 characters.") + f"Lines should be no longer than {max_width} characters.") else: if f.full_name in OVERLONG_BODY: - fail(f"Remove {f.full_name!r} from OVERLONG_BODY!\n") + warn(f"Remove {f.full_name!r} from OVERLONG_BODY!\n") parameters_marker_count = len(f.docstring.split('{parameters}')) - 1 if parameters_marker_count > 1: diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index e80e2f5f13f648..cdc8e05e4c2b1a 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -167,6 +167,19 @@ def methoddef_flags(self) -> str | None: flags.append('METH_COEXIST') return '|'.join(flags) + @property + def docstring_line_width(self) -> int: + """PEP 8 requires that docstrings are limited to 72 characters: + + The Python standard library is conservative and requires + limiting lines to 79 characters (and docstrings to 72). + + Methods have an extra level of indentation, so we use 68. + """ + if self.cls is not None and not self.kind.new_or_init: + return 68 + return 72 + def __repr__(self) -> str: return f'' From b3acb9129368d6951fa374553adb0fb50499180b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 12 Aug 2025 19:50:03 +0100 Subject: [PATCH 5/8] Revert repr change --- Tools/clinic/libclinic/errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/libclinic/errors.py b/Tools/clinic/libclinic/errors.py index 0dcdb1045611c2..f06bdfbd864b2c 100644 --- a/Tools/clinic/libclinic/errors.py +++ b/Tools/clinic/libclinic/errors.py @@ -15,7 +15,7 @@ def __post_init__(self) -> None: def report(self, *, warn_only: bool = False) -> str: msg = "Warning" if warn_only else "Error" if self.filename is not None: - msg += f" in file '{self.filename}'" + msg += f" in file {self.filename!r}" if self.lineno is not None: msg += f" on line {self.lineno}" msg += ":\n" From 980b95aad25cd4a816f69aae463ec8b6ade11a43 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:02:06 +0100 Subject: [PATCH 6/8] post-merge --- Tools/clinic/libclinic/_overlong_docstrings.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tools/clinic/libclinic/_overlong_docstrings.py b/Tools/clinic/libclinic/_overlong_docstrings.py index 348c8f732aa8d1..7aff997561df71 100644 --- a/Tools/clinic/libclinic/_overlong_docstrings.py +++ b/Tools/clinic/libclinic/_overlong_docstrings.py @@ -37,6 +37,8 @@ '_hashlib.pbkdf2_hmac', '_heapq.heappushpop', '_hmac.HMAC.hexdigest', + '_interpreters.get_config', + '_interpreters.is_shareable', '_io._BufferedIOBase.read1', '_io.FileIO.truncate', '_lzma._decode_filter_properties', @@ -223,6 +225,7 @@ '_jit.is_available', '_jit.is_enabled', 'marshal.dumps', + 'sys._clear_type_descriptors', 'sys._current_exceptions', 'sys._current_frames', 'sys._setprofileallthreads', @@ -301,6 +304,8 @@ '_hashlib.HMAC.hexdigest', '_heapq.heappushpop_max', '_hmac.HMAC.hexdigest', + '_interpreters.capture_exception', + '_interpreters.run_func', '_io._IOBase.seek', '_io._IOBase.truncate', '_io._TextIOBase.detach', From 3bc4f20825e539cacf2bae2cedfb0e06266667ce Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:40:28 +0100 Subject: [PATCH 7/8] 72/76 --- .../clinic/libclinic/_overlong_docstrings.py | 230 ------------------ Tools/clinic/libclinic/function.py | 4 +- 2 files changed, 2 insertions(+), 232 deletions(-) diff --git a/Tools/clinic/libclinic/_overlong_docstrings.py b/Tools/clinic/libclinic/_overlong_docstrings.py index 7aff997561df71..5ca335fab2875c 100644 --- a/Tools/clinic/libclinic/_overlong_docstrings.py +++ b/Tools/clinic/libclinic/_overlong_docstrings.py @@ -7,51 +7,31 @@ '_abc._abc_instancecheck', '_abc._abc_register', '_abc._abc_subclasscheck', - '_asyncio._swap_current_task', '_codecs.lookup', - '_collections.deque.rotate', '_ctypes.byref', - '_curses.assume_default_colors', '_curses.can_change_color', - '_curses.has_extended_color_support', - '_curses.has_ic', - '_curses.has_key', '_curses.is_term_resized', '_curses.mousemask', - '_curses.pair_content', - '_curses.pair_number', - '_curses.putp', '_curses.reset_prog_mode', '_curses.reset_shell_mode', - '_curses.start_color', '_curses.termname', '_curses.window.enclose', - '_curses.window.is_linetouched', - '_curses.window.putwin', - '_elementtree._set_factories', '_functools.reduce', '_gdbm.gdbm.setdefault', '_hashlib.HMAC.hexdigest', '_hashlib.openssl_shake_128', '_hashlib.openssl_shake_256', '_hashlib.pbkdf2_hmac', - '_heapq.heappushpop', '_hmac.HMAC.hexdigest', - '_interpreters.get_config', '_interpreters.is_shareable', '_io._BufferedIOBase.read1', - '_io.FileIO.truncate', '_lzma._decode_filter_properties', - '_opcode.has_name', '_remote_debugging.RemoteUnwinder.__init__', '_remote_debugging.RemoteUnwinder.get_all_awaited_by', '_remote_debugging.RemoteUnwinder.get_async_stack_trace', - '_socket.if_indextoname', '_socket.inet_aton', - '_sqlite3.Connection.set_trace_callback', '_sre.SRE_Match.expand', '_sre.SRE_Match.groupdict', - '_sre.SRE_Match.span', '_sre.SRE_Pattern.finditer', '_sre.SRE_Pattern.search', '_sre.SRE_Pattern.sub', @@ -66,81 +46,44 @@ '_testcapi.VectorCallClass.set_vectorcall', '_tkinter.getbusywaitinterval', '_tkinter.setbusywaitinterval', - '_tracemalloc.get_traced_memory', - '_tracemalloc.is_tracing', '_tracemalloc.reset_peak', '_zstd.get_frame_size', '_zstd.set_parameter_types', - '_zstd.ZstdCompressor.set_pledged_input_size', '_zstd.ZstdDecompressor.decompress', 'array.array.buffer_info', 'array.array.frombytes', 'array.array.fromfile', 'array.array.tobytes', 'cmath.isfinite', - 'datetime.date.strptime', 'datetime.datetime.strptime', - 'datetime.time.strptime', - 'gc.freeze', 'gc.get_objects', - 'itertools.batched.__new__', 'itertools.chain.from_iterable', 'itertools.combinations_with_replacement.__new__', - 'itertools.count.__new__', 'itertools.cycle.__new__', - 'itertools.groupby.__new__', 'itertools.starmap.__new__', 'itertools.takewhile.__new__', 'math.comb', - 'math.isinf', - 'math.nextafter', 'math.perm', - 'os._exit', - 'os._fcopyfile', - 'os._findfirstfile', - 'os._getdiskusage', 'os.getresgid', - 'os.getresuid', - 'os.lchmod', - 'os.login_tty', 'os.lstat', - 'os.posix_fallocate', 'os.pread', - 'os.preadv', 'os.pwritev', 'os.sched_getaffinity', 'os.sched_rr_get_interval', 'os.timerfd_gettime', 'os.timerfd_gettime_ns', 'os.urandom', - 'os.WIFCONTINUED', 'os.WIFEXITED', - 'os.writev', - 'os.WSTOPSIG', 'os.WTERMSIG', 'pwd.getpwall', 'pyexpat.xmlparser.ExternalEntityParserCreate', - 'pyexpat.xmlparser.GetInputContext', 'pyexpat.xmlparser.GetReparseDeferralEnabled', 'pyexpat.xmlparser.SetParamEntityParsing', - 'pyexpat.xmlparser.SetReparseDeferralEnabled', 'pyexpat.xmlparser.UseForeignDTD', - 'readline.get_history_length', 'readline.redisplay', - 'readline.set_history_length', - 'select.epoll.register', 'signal.set_wakeup_fd', - 'unpack', # struct.unpack - 'unpack_from', # struct.unpack_from - 'termios.tcdrain', - 'unicodedata.UCD.bidirectional', - 'unicodedata.UCD.category', 'unicodedata.UCD.combining', 'unicodedata.UCD.decomposition', - 'unicodedata.UCD.east_asian_width', - 'unicodedata.UCD.is_normalized', - 'unicodedata.UCD.mirrored', - 'zlib.Decompress.decompress', 'zoneinfo.ZoneInfo.dst', 'zoneinfo.ZoneInfo.tzname', 'zoneinfo.ZoneInfo.utcoffset', @@ -159,132 +102,65 @@ 'bytearray.split', 'bytearray.splitlines', 'bytearray.startswith', - 'bytearray.translate', 'bytes.count', 'bytes.endswith', 'bytes.find', 'bytes.index', 'bytes.maketrans', - 'bytes.removeprefix', - 'bytes.removesuffix', 'bytes.rfind', 'bytes.rindex', - 'bytes.rsplit', - 'bytes.split', - 'bytes.splitlines', 'bytes.startswith', - 'bytes.translate', 'code.replace', 'complex.conjugate', - 'dict.fromkeys', 'dict.pop', 'float.as_integer_ratio', - 'frame.f_generator', 'frame.f_trace', 'int.bit_count', - 'int.is_integer', 'OrderedDict.fromkeys', 'OrderedDict.pop', - 'set.difference', - 'set.symmetric_difference', 'set.symmetric_difference_update', - 'str.__format__', 'str.count', 'str.endswith', 'str.find', 'str.index', - 'str.isalnum', - 'str.isascii', - 'str.isidentifier', 'str.isprintable', 'str.rfind', 'str.rindex', 'str.rsplit', 'str.split', - 'str.splitlines', 'str.startswith', 'str.strip', 'str.swapcase', - 'str.translate', 'str.zfill', # PC/ 'msvcrt.kbhit', # Python/ - 'chr', - 'compile', - 'isinstance', - 'pow', - 'sum', - '_contextvars.Context.get', - '_contextvars.ContextVar.set', - '_imp._override_multi_interp_extensions_check', - '_imp.find_frozen', '_jit.is_active', '_jit.is_available', '_jit.is_enabled', 'marshal.dumps', - 'sys._clear_type_descriptors', 'sys._current_exceptions', - 'sys._current_frames', 'sys._setprofileallthreads', 'sys._settraceallthreads', - 'sys.get_int_max_str_digits', - 'sys.set_int_max_str_digits', )) OVERLONG_BODY = frozenset(( - # Modules/ - '_abc.get_cache_token', - '_asyncio.Future.add_done_callback', - '_asyncio.Future.cancel', - '_asyncio.Future.done', - '_asyncio.Future.result', - '_bisect.bisect_left', - '_bisect.bisect_right', '_bz2.BZ2Decompressor.decompress', - '_codecs.decode', - '_codecs.encode', - '_codecs.lookup_error', - '_codecs.register', - '_codecs.register_error', - '_curses.cbreak', '_curses.color_content', - '_curses.color_pair', - '_curses.curs_set', - '_curses.def_shell_mode', - '_curses.echo', '_curses.flash', - '_curses.flushinp', - '_curses.get_escdelay', - '_curses.get_tabsize', - '_curses.init_pair', '_curses.longname', - '_curses.mouseinterval', - '_curses.mousemask', - '_curses.newwin', - '_curses.nl', - '_curses.nonl', - '_curses.raw', '_curses.resize_term', - '_curses.resizeterm', - '_curses.set_escdelay', - '_curses.set_tabsize', - '_curses.start_color', - '_curses.tigetnum', - '_curses.tigetstr', '_curses.use_env', '_curses.window.border', - '_curses.window.box', '_curses.window.derwin', '_curses.window.getch', '_curses.window.getkey', '_curses.window.inch', '_curses.window.insch', '_curses.window.insnstr', - '_curses.window.insstr', '_curses.window.is_linetouched', '_curses.window.noutrefresh', '_curses.window.overlay', @@ -294,70 +170,38 @@ '_curses.window.subwin', '_curses.window.touchline', '_curses_panel.panel.hide', - '_curses_panel.update_panels', - '_dbm.dbm.setdefault', '_functools.reduce', - '_gdbm.gdbm.firstkey', - '_gdbm.gdbm.nextkey', - '_gdbm.gdbm.reorganize', - '_hashlib.get_fips_mode', '_hashlib.HMAC.hexdigest', - '_heapq.heappushpop_max', '_hmac.HMAC.hexdigest', '_interpreters.capture_exception', - '_interpreters.run_func', '_io._IOBase.seek', - '_io._IOBase.truncate', '_io._TextIOBase.detach', - '_io._TextIOBase.read', - '_io._WindowsConsoleIO.__init__', - '_io.BytesIO.read1', - '_io.BytesIO.writelines', - '_io.FileIO.__init__', - '_io.FileIO.close', '_io.FileIO.read', '_io.FileIO.readall', '_io.FileIO.seek', - '_io.FileIO.write', '_io.open', '_io.open_code', - '_io.StringIO.seek', - '_io.TextIOWrapper.tell', '_lzma.LZMADecompressor.decompress', '_multibytecodec.MultibyteCodec.decode', '_multibytecodec.MultibyteCodec.encode', - '_overlapped.Overlapped.getresult', - '_posixshmem.shm_unlink', '_posixsubprocess.fork_exec', - '_queue.SimpleQueue.get', - '_queue.SimpleQueue.put', '_remote_debugging.RemoteUnwinder.__init__', '_remote_debugging.RemoteUnwinder.get_all_awaited_by', '_remote_debugging.RemoteUnwinder.get_async_stack_trace', '_remote_debugging.RemoteUnwinder.get_stack_trace', '_socket.socket.send', - '_socket.socket.sendall', - '_socket.socket.sendmsg', '_sqlite3.Blob.read', '_sqlite3.Blob.seek', '_sqlite3.Blob.write', - '_sqlite3.Connection.__exit__', '_sqlite3.Connection.deserialize', '_sqlite3.Connection.serialize', '_sqlite3.Connection.set_progress_handler', '_sqlite3.Connection.setlimit', - '_ssl._SSLContext.cert_store_stats', - '_ssl._SSLContext.get_ca_certs', '_ssl._SSLContext.sni_callback', '_ssl._SSLSocket.context', '_ssl._SSLSocket.get_channel_binding', '_ssl._SSLSocket.sendfile', - '_ssl.enum_certificates', - '_ssl.RAND_status', - '_testlimitedcapi.test_long_as_size_t', - '_testmultiphase.StateAccessType.get_defining_module', '_tkinter.setbusywaitinterval', - '_zstd.ZstdCompressor.__new__', '_zstd.ZstdCompressor.compress', '_zstd.ZstdCompressor.flush', '_zstd.ZstdCompressor.set_pledged_input_size', @@ -368,87 +212,43 @@ '_zstd.ZstdDict.as_digested_dict', '_zstd.ZstdDict.as_prefix', '_zstd.ZstdDict.as_undigested_dict', - 'array.array.buffer_info', 'array.array.byteswap', 'array.array.fromunicode', 'array.array.tounicode', 'binascii.a2b_base64', 'cmath.isclose', - 'cmath.log', 'datetime.date.fromtimestamp', - 'datetime.datetime.__new__', 'datetime.datetime.fromtimestamp', - 'datetime.time.isoformat', 'datetime.time.strftime', - 'fcntl.fcntl', 'fcntl.ioctl', 'fcntl.lockf', 'gc.freeze', - 'gc.get_objects', 'itertools.combinations_with_replacement.__new__', - 'itertools.compress.__new__', 'math.nextafter', - 'os.abort', - 'os.chdir', - 'os.chflags', - 'os.chown', 'os.fspath', - 'os.getppid', - 'os.getxattr', - 'os.initgroups', - 'os.lchmod', 'os.link', 'os.listdir', 'os.listxattr', 'os.lseek', - 'os.mkdir', - 'os.mkfifo', 'os.mknod', - 'os.open', - 'os.pathconf', - 'os.pidfd_open', - 'os.posix_fadvise', - 'os.posix_fallocate', - 'os.posix_openpt', 'os.preadv', 'os.pwritev', 'os.readinto', - 'os.readlink', - 'os.remove', - 'os.removexattr', 'os.rename', 'os.replace', - 'os.rmdir', - 'os.scandir', 'os.setxattr', - 'os.statvfs', - 'os.symlink', - 'os.truncate', - 'os.unlink', - 'os.utime', - 'os.waitid', - 'os.waitstatus_to_exitcode', 'pyexpat.xmlparser.GetInputContext', 'pyexpat.xmlparser.UseForeignDTD', 'select.devpoll', - 'select.devpoll.poll', - 'select.epoll.poll', 'select.poll', - 'select.poll.poll', 'select.select', 'signal.setitimer', 'signal.signal', - 'signal.sigtimedwait', - 'signal.sigwait', - 'Struct.__init__', # struct.Struct.__init__ - 'Struct.unpack', # struct.Struct.unpack 'termios.tcsetwinsize', 'zlib.Decompress.decompress', 'zlib.ZlibDecompressor.decompress', # Objects/ - 'bytearray.fromhex', - 'bytearray.join', 'bytearray.maketrans', 'bytearray.partition', 'bytearray.replace', @@ -456,27 +256,17 @@ 'bytearray.rsplit', 'bytearray.splitlines', 'bytearray.strip', - 'bytearray.translate', 'bytes.maketrans', 'bytes.partition', - 'bytes.removeprefix', - 'bytes.removesuffix', 'bytes.replace', 'bytes.rpartition', 'bytes.rsplit', 'bytes.splitlines', 'bytes.strip', - 'bytes.translate', - 'code._varname_from_oparg', 'float.__getformat__', 'list.sort', 'memoryview.tobytes', - 'OrderedDict.popitem', 'str.capitalize', - 'str.center', - 'str.count', - 'str.find', - 'str.index', 'str.isalnum', 'str.isalpha', 'str.isdecimal', @@ -487,17 +277,10 @@ 'str.isspace', 'str.isupper', 'str.join', - 'str.ljust', - 'str.maketrans', 'str.partition', 'str.removeprefix', - 'str.removesuffix', 'str.replace', - 'str.rfind', - 'str.rindex', - 'str.rjust', 'str.rpartition', - 'str.split', 'str.splitlines', 'str.title', 'str.translate', @@ -507,23 +290,10 @@ # Python/ '__import__', - 'compile', - 'globals', - 'hash', - 'input', - 'isinstance', - 'issubclass', - 'locals', - 'pow', - 'round', - 'sum', - '_contextvars.Context.get', '_contextvars.ContextVar.get', '_contextvars.ContextVar.reset', '_contextvars.ContextVar.set', '_imp.acquire_lock', 'marshal.dumps', - 'marshal.loads', 'sys._stats_dump', - 'sys.remote_exec', )) diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index cdc8e05e4c2b1a..0b2b72ec95a910 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -177,8 +177,8 @@ def docstring_line_width(self) -> int: Methods have an extra level of indentation, so we use 68. """ if self.cls is not None and not self.kind.new_or_init: - return 68 - return 72 + return 72 + return 76 def __repr__(self) -> str: return f'' From 2216db92c0532120a6d75201cd0a80ea47bf735e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:51:49 +0100 Subject: [PATCH 8/8] Update docstring_line_width docstring --- Tools/clinic/libclinic/function.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index 0b2b72ec95a910..4280af0c4c9b49 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -169,12 +169,12 @@ def methoddef_flags(self) -> str | None: @property def docstring_line_width(self) -> int: - """PEP 8 requires that docstrings are limited to 72 characters: + """Return the maximum line width for docstring lines. - The Python standard library is conservative and requires - limiting lines to 79 characters (and docstrings to 72). - - Methods have an extra level of indentation, so we use 68. + Pydoc adds indentation when displaying functions and methods. + To keep the total width of within 80 characters, we use a + maximum of 76 characters for global functions and classes, + and 72 characters for methods. """ if self.cls is not None and not self.kind.new_or_init: return 72