17db96d56Sopenharmony_ci# -*- coding: utf-8 -*- 27db96d56Sopenharmony_ci""" 37db96d56Sopenharmony_ci pyspecific.py 47db96d56Sopenharmony_ci ~~~~~~~~~~~~~ 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ci Sphinx extension with Python doc-specific markup. 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ci :copyright: 2008-2014 by Georg Brandl. 97db96d56Sopenharmony_ci :license: Python license. 107db96d56Sopenharmony_ci""" 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ciimport re 137db96d56Sopenharmony_ciimport io 147db96d56Sopenharmony_cifrom os import getenv, path 157db96d56Sopenharmony_cifrom time import asctime 167db96d56Sopenharmony_cifrom pprint import pformat 177db96d56Sopenharmony_cifrom docutils.io import StringOutput 187db96d56Sopenharmony_cifrom docutils.parsers.rst import Directive 197db96d56Sopenharmony_cifrom docutils.utils import new_document 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_cifrom docutils import nodes, utils 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_cifrom sphinx import addnodes 247db96d56Sopenharmony_cifrom sphinx.builders import Builder 257db96d56Sopenharmony_citry: 267db96d56Sopenharmony_ci from sphinx.errors import NoUri 277db96d56Sopenharmony_ciexcept ImportError: 287db96d56Sopenharmony_ci from sphinx.environment import NoUri 297db96d56Sopenharmony_cifrom sphinx.locale import _ as sphinx_gettext 307db96d56Sopenharmony_cifrom sphinx.util import status_iterator, logging 317db96d56Sopenharmony_cifrom sphinx.util.docutils import SphinxDirective 327db96d56Sopenharmony_cifrom sphinx.util.nodes import split_explicit_title 337db96d56Sopenharmony_cifrom sphinx.writers.text import TextWriter, TextTranslator 347db96d56Sopenharmony_cifrom sphinx.writers.latex import LaTeXTranslator 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_citry: 377db96d56Sopenharmony_ci from sphinx.domains.python import PyFunction, PyMethod 387db96d56Sopenharmony_ciexcept ImportError: 397db96d56Sopenharmony_ci from sphinx.domains.python import PyClassmember as PyMethod 407db96d56Sopenharmony_ci from sphinx.domains.python import PyModulelevel as PyFunction 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci# Support for checking for suspicious markup 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ciimport suspicious 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ciISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s' 487db96d56Sopenharmony_ciGH_ISSUE_URI = 'https://github.com/python/cpython/issues/%s' 497db96d56Sopenharmony_ciSOURCE_URI = 'https://github.com/python/cpython/tree/3.11/%s' 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ci# monkey-patch reST parser to disable alphabetic and roman enumerated lists 527db96d56Sopenharmony_cifrom docutils.parsers.rst.states import Body 537db96d56Sopenharmony_ciBody.enum.converters['loweralpha'] = \ 547db96d56Sopenharmony_ci Body.enum.converters['upperalpha'] = \ 557db96d56Sopenharmony_ci Body.enum.converters['lowerroman'] = \ 567db96d56Sopenharmony_ci Body.enum.converters['upperroman'] = lambda x: None 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_ci# Support for marking up and linking to bugs.python.org issues 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_cidef issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): 627db96d56Sopenharmony_ci issue = utils.unescape(text) 637db96d56Sopenharmony_ci # sanity check: there are no bpo issues within these two values 647db96d56Sopenharmony_ci if 47261 < int(issue) < 400000: 657db96d56Sopenharmony_ci msg = inliner.reporter.error(f'The BPO ID {text!r} seems too high -- ' 667db96d56Sopenharmony_ci 'use :gh:`...` for GitHub IDs', line=lineno) 677db96d56Sopenharmony_ci prb = inliner.problematic(rawtext, rawtext, msg) 687db96d56Sopenharmony_ci return [prb], [msg] 697db96d56Sopenharmony_ci text = 'bpo-' + issue 707db96d56Sopenharmony_ci refnode = nodes.reference(text, text, refuri=ISSUE_URI % issue) 717db96d56Sopenharmony_ci return [refnode], [] 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci# Support for marking up and linking to GitHub issues 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_cidef gh_issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): 777db96d56Sopenharmony_ci issue = utils.unescape(text) 787db96d56Sopenharmony_ci # sanity check: all GitHub issues have ID >= 32426 797db96d56Sopenharmony_ci # even though some of them are also valid BPO IDs 807db96d56Sopenharmony_ci if int(issue) < 32426: 817db96d56Sopenharmony_ci msg = inliner.reporter.error(f'The GitHub ID {text!r} seems too low -- ' 827db96d56Sopenharmony_ci 'use :issue:`...` for BPO IDs', line=lineno) 837db96d56Sopenharmony_ci prb = inliner.problematic(rawtext, rawtext, msg) 847db96d56Sopenharmony_ci return [prb], [msg] 857db96d56Sopenharmony_ci text = 'gh-' + issue 867db96d56Sopenharmony_ci refnode = nodes.reference(text, text, refuri=GH_ISSUE_URI % issue) 877db96d56Sopenharmony_ci return [refnode], [] 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci# Support for linking to Python source files easily 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_cidef source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): 937db96d56Sopenharmony_ci has_t, title, target = split_explicit_title(text) 947db96d56Sopenharmony_ci title = utils.unescape(title) 957db96d56Sopenharmony_ci target = utils.unescape(target) 967db96d56Sopenharmony_ci refnode = nodes.reference(title, title, refuri=SOURCE_URI % target) 977db96d56Sopenharmony_ci return [refnode], [] 987db96d56Sopenharmony_ci 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci# Support for marking up implementation details 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ciclass ImplementationDetail(Directive): 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci has_content = True 1057db96d56Sopenharmony_ci final_argument_whitespace = True 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci # This text is copied to templates/dummy.html 1087db96d56Sopenharmony_ci label_text = 'CPython implementation detail:' 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_ci def run(self): 1117db96d56Sopenharmony_ci self.assert_has_content() 1127db96d56Sopenharmony_ci pnode = nodes.compound(classes=['impl-detail']) 1137db96d56Sopenharmony_ci label = sphinx_gettext(self.label_text) 1147db96d56Sopenharmony_ci content = self.content 1157db96d56Sopenharmony_ci add_text = nodes.strong(label, label) 1167db96d56Sopenharmony_ci self.state.nested_parse(content, self.content_offset, pnode) 1177db96d56Sopenharmony_ci content = nodes.inline(pnode[0].rawsource, translatable=True) 1187db96d56Sopenharmony_ci content.source = pnode[0].source 1197db96d56Sopenharmony_ci content.line = pnode[0].line 1207db96d56Sopenharmony_ci content += pnode[0].children 1217db96d56Sopenharmony_ci pnode[0].replace_self(nodes.paragraph( 1227db96d56Sopenharmony_ci '', '', add_text, nodes.Text(' '), content, translatable=False)) 1237db96d56Sopenharmony_ci return [pnode] 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci# Support for documenting platform availability 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ciclass Availability(SphinxDirective): 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci has_content = True 1317db96d56Sopenharmony_ci required_arguments = 1 1327db96d56Sopenharmony_ci optional_arguments = 0 1337db96d56Sopenharmony_ci final_argument_whitespace = True 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci # known platform, libc, and threading implementations 1367db96d56Sopenharmony_ci known_platforms = frozenset({ 1377db96d56Sopenharmony_ci "AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD", 1387db96d56Sopenharmony_ci "Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris", "Unix", "VxWorks", 1397db96d56Sopenharmony_ci "WASI", "Windows", "macOS", 1407db96d56Sopenharmony_ci # libc 1417db96d56Sopenharmony_ci "BSD libc", "glibc", "musl", 1427db96d56Sopenharmony_ci # POSIX platforms with pthreads 1437db96d56Sopenharmony_ci "pthreads", 1447db96d56Sopenharmony_ci }) 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci def run(self): 1477db96d56Sopenharmony_ci availability_ref = ':ref:`Availability <availability>`: ' 1487db96d56Sopenharmony_ci avail_nodes, avail_msgs = self.state.inline_text( 1497db96d56Sopenharmony_ci availability_ref + self.arguments[0], 1507db96d56Sopenharmony_ci self.lineno) 1517db96d56Sopenharmony_ci pnode = nodes.paragraph(availability_ref + self.arguments[0], 1527db96d56Sopenharmony_ci '', *avail_nodes, *avail_msgs) 1537db96d56Sopenharmony_ci self.set_source_info(pnode) 1547db96d56Sopenharmony_ci cnode = nodes.container("", pnode, classes=["availability"]) 1557db96d56Sopenharmony_ci self.set_source_info(cnode) 1567db96d56Sopenharmony_ci if self.content: 1577db96d56Sopenharmony_ci self.state.nested_parse(self.content, self.content_offset, cnode) 1587db96d56Sopenharmony_ci self.parse_platforms() 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci return [cnode] 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci def parse_platforms(self): 1637db96d56Sopenharmony_ci """Parse platform information from arguments 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci Arguments is a comma-separated string of platforms. A platform may 1667db96d56Sopenharmony_ci be prefixed with "not " to indicate that a feature is not available. 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci Example:: 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci .. availability:: Windows, Linux >= 4.2, not Emscripten, not WASI 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not 1737db96d56Sopenharmony_ci parsed into separate tokens. 1747db96d56Sopenharmony_ci """ 1757db96d56Sopenharmony_ci platforms = {} 1767db96d56Sopenharmony_ci for arg in self.arguments[0].rstrip(".").split(","): 1777db96d56Sopenharmony_ci arg = arg.strip() 1787db96d56Sopenharmony_ci platform, _, version = arg.partition(" >= ") 1797db96d56Sopenharmony_ci if platform.startswith("not "): 1807db96d56Sopenharmony_ci version = False 1817db96d56Sopenharmony_ci platform = platform[4:] 1827db96d56Sopenharmony_ci elif not version: 1837db96d56Sopenharmony_ci version = True 1847db96d56Sopenharmony_ci platforms[platform] = version 1857db96d56Sopenharmony_ci 1867db96d56Sopenharmony_ci unknown = set(platforms).difference(self.known_platforms) 1877db96d56Sopenharmony_ci if unknown: 1887db96d56Sopenharmony_ci cls = type(self) 1897db96d56Sopenharmony_ci logger = logging.getLogger(cls.__qualname__) 1907db96d56Sopenharmony_ci logger.warn( 1917db96d56Sopenharmony_ci f"Unknown platform(s) or syntax '{' '.join(sorted(unknown))}' " 1927db96d56Sopenharmony_ci f"in '.. availability:: {self.arguments[0]}', see " 1937db96d56Sopenharmony_ci f"{__file__}:{cls.__qualname__}.known_platforms for a set " 1947db96d56Sopenharmony_ci "known platforms." 1957db96d56Sopenharmony_ci ) 1967db96d56Sopenharmony_ci 1977db96d56Sopenharmony_ci return platforms 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_ci# Support for documenting audit event 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_cidef audit_events_purge(app, env, docname): 2047db96d56Sopenharmony_ci """This is to remove from env.all_audit_events old traces of removed 2057db96d56Sopenharmony_ci documents. 2067db96d56Sopenharmony_ci """ 2077db96d56Sopenharmony_ci if not hasattr(env, 'all_audit_events'): 2087db96d56Sopenharmony_ci return 2097db96d56Sopenharmony_ci fresh_all_audit_events = {} 2107db96d56Sopenharmony_ci for name, event in env.all_audit_events.items(): 2117db96d56Sopenharmony_ci event["source"] = [(d, t) for d, t in event["source"] if d != docname] 2127db96d56Sopenharmony_ci if event["source"]: 2137db96d56Sopenharmony_ci # Only keep audit_events that have at least one source. 2147db96d56Sopenharmony_ci fresh_all_audit_events[name] = event 2157db96d56Sopenharmony_ci env.all_audit_events = fresh_all_audit_events 2167db96d56Sopenharmony_ci 2177db96d56Sopenharmony_ci 2187db96d56Sopenharmony_cidef audit_events_merge(app, env, docnames, other): 2197db96d56Sopenharmony_ci """In Sphinx parallel builds, this merges env.all_audit_events from 2207db96d56Sopenharmony_ci subprocesses. 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_ci all_audit_events is a dict of names, with values like: 2237db96d56Sopenharmony_ci {'source': [(docname, target), ...], 'args': args} 2247db96d56Sopenharmony_ci """ 2257db96d56Sopenharmony_ci if not hasattr(other, 'all_audit_events'): 2267db96d56Sopenharmony_ci return 2277db96d56Sopenharmony_ci if not hasattr(env, 'all_audit_events'): 2287db96d56Sopenharmony_ci env.all_audit_events = {} 2297db96d56Sopenharmony_ci for name, value in other.all_audit_events.items(): 2307db96d56Sopenharmony_ci if name in env.all_audit_events: 2317db96d56Sopenharmony_ci env.all_audit_events[name]["source"].extend(value["source"]) 2327db96d56Sopenharmony_ci else: 2337db96d56Sopenharmony_ci env.all_audit_events[name] = value 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci 2367db96d56Sopenharmony_ciclass AuditEvent(Directive): 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ci has_content = True 2397db96d56Sopenharmony_ci required_arguments = 1 2407db96d56Sopenharmony_ci optional_arguments = 2 2417db96d56Sopenharmony_ci final_argument_whitespace = True 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ci _label = [ 2447db96d56Sopenharmony_ci "Raises an :ref:`auditing event <auditing>` {name} with no arguments.", 2457db96d56Sopenharmony_ci "Raises an :ref:`auditing event <auditing>` {name} with argument {args}.", 2467db96d56Sopenharmony_ci "Raises an :ref:`auditing event <auditing>` {name} with arguments {args}.", 2477db96d56Sopenharmony_ci ] 2487db96d56Sopenharmony_ci 2497db96d56Sopenharmony_ci @property 2507db96d56Sopenharmony_ci def logger(self): 2517db96d56Sopenharmony_ci cls = type(self) 2527db96d56Sopenharmony_ci return logging.getLogger(cls.__module__ + "." + cls.__name__) 2537db96d56Sopenharmony_ci 2547db96d56Sopenharmony_ci def run(self): 2557db96d56Sopenharmony_ci name = self.arguments[0] 2567db96d56Sopenharmony_ci if len(self.arguments) >= 2 and self.arguments[1]: 2577db96d56Sopenharmony_ci args = (a.strip() for a in self.arguments[1].strip("'\"").split(",")) 2587db96d56Sopenharmony_ci args = [a for a in args if a] 2597db96d56Sopenharmony_ci else: 2607db96d56Sopenharmony_ci args = [] 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci label = sphinx_gettext(self._label[min(2, len(args))]) 2637db96d56Sopenharmony_ci text = label.format(name="``{}``".format(name), 2647db96d56Sopenharmony_ci args=", ".join("``{}``".format(a) for a in args if a)) 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci env = self.state.document.settings.env 2677db96d56Sopenharmony_ci if not hasattr(env, 'all_audit_events'): 2687db96d56Sopenharmony_ci env.all_audit_events = {} 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci new_info = { 2717db96d56Sopenharmony_ci 'source': [], 2727db96d56Sopenharmony_ci 'args': args 2737db96d56Sopenharmony_ci } 2747db96d56Sopenharmony_ci info = env.all_audit_events.setdefault(name, new_info) 2757db96d56Sopenharmony_ci if info is not new_info: 2767db96d56Sopenharmony_ci if not self._do_args_match(info['args'], new_info['args']): 2777db96d56Sopenharmony_ci self.logger.warn( 2787db96d56Sopenharmony_ci "Mismatched arguments for audit-event {}: {!r} != {!r}" 2797db96d56Sopenharmony_ci .format(name, info['args'], new_info['args']) 2807db96d56Sopenharmony_ci ) 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci ids = [] 2837db96d56Sopenharmony_ci try: 2847db96d56Sopenharmony_ci target = self.arguments[2].strip("\"'") 2857db96d56Sopenharmony_ci except (IndexError, TypeError): 2867db96d56Sopenharmony_ci target = None 2877db96d56Sopenharmony_ci if not target: 2887db96d56Sopenharmony_ci target = "audit_event_{}_{}".format( 2897db96d56Sopenharmony_ci re.sub(r'\W', '_', name), 2907db96d56Sopenharmony_ci len(info['source']), 2917db96d56Sopenharmony_ci ) 2927db96d56Sopenharmony_ci ids.append(target) 2937db96d56Sopenharmony_ci 2947db96d56Sopenharmony_ci info['source'].append((env.docname, target)) 2957db96d56Sopenharmony_ci 2967db96d56Sopenharmony_ci pnode = nodes.paragraph(text, classes=["audit-hook"], ids=ids) 2977db96d56Sopenharmony_ci pnode.line = self.lineno 2987db96d56Sopenharmony_ci if self.content: 2997db96d56Sopenharmony_ci self.state.nested_parse(self.content, self.content_offset, pnode) 3007db96d56Sopenharmony_ci else: 3017db96d56Sopenharmony_ci n, m = self.state.inline_text(text, self.lineno) 3027db96d56Sopenharmony_ci pnode.extend(n + m) 3037db96d56Sopenharmony_ci 3047db96d56Sopenharmony_ci return [pnode] 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ci # This list of sets are allowable synonyms for event argument names. 3077db96d56Sopenharmony_ci # If two names are in the same set, they are treated as equal for the 3087db96d56Sopenharmony_ci # purposes of warning. This won't help if number of arguments is 3097db96d56Sopenharmony_ci # different! 3107db96d56Sopenharmony_ci _SYNONYMS = [ 3117db96d56Sopenharmony_ci {"file", "path", "fd"}, 3127db96d56Sopenharmony_ci ] 3137db96d56Sopenharmony_ci 3147db96d56Sopenharmony_ci def _do_args_match(self, args1, args2): 3157db96d56Sopenharmony_ci if args1 == args2: 3167db96d56Sopenharmony_ci return True 3177db96d56Sopenharmony_ci if len(args1) != len(args2): 3187db96d56Sopenharmony_ci return False 3197db96d56Sopenharmony_ci for a1, a2 in zip(args1, args2): 3207db96d56Sopenharmony_ci if a1 == a2: 3217db96d56Sopenharmony_ci continue 3227db96d56Sopenharmony_ci if any(a1 in s and a2 in s for s in self._SYNONYMS): 3237db96d56Sopenharmony_ci continue 3247db96d56Sopenharmony_ci return False 3257db96d56Sopenharmony_ci return True 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ciclass audit_event_list(nodes.General, nodes.Element): 3297db96d56Sopenharmony_ci pass 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ciclass AuditEventListDirective(Directive): 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci def run(self): 3357db96d56Sopenharmony_ci return [audit_event_list('')] 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_ci# Support for documenting decorators 3397db96d56Sopenharmony_ci 3407db96d56Sopenharmony_ciclass PyDecoratorMixin(object): 3417db96d56Sopenharmony_ci def handle_signature(self, sig, signode): 3427db96d56Sopenharmony_ci ret = super(PyDecoratorMixin, self).handle_signature(sig, signode) 3437db96d56Sopenharmony_ci signode.insert(0, addnodes.desc_addname('@', '@')) 3447db96d56Sopenharmony_ci return ret 3457db96d56Sopenharmony_ci 3467db96d56Sopenharmony_ci def needs_arglist(self): 3477db96d56Sopenharmony_ci return False 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci 3507db96d56Sopenharmony_ciclass PyDecoratorFunction(PyDecoratorMixin, PyFunction): 3517db96d56Sopenharmony_ci def run(self): 3527db96d56Sopenharmony_ci # a decorator function is a function after all 3537db96d56Sopenharmony_ci self.name = 'py:function' 3547db96d56Sopenharmony_ci return PyFunction.run(self) 3557db96d56Sopenharmony_ci 3567db96d56Sopenharmony_ci 3577db96d56Sopenharmony_ci# TODO: Use sphinx.domains.python.PyDecoratorMethod when possible 3587db96d56Sopenharmony_ciclass PyDecoratorMethod(PyDecoratorMixin, PyMethod): 3597db96d56Sopenharmony_ci def run(self): 3607db96d56Sopenharmony_ci self.name = 'py:method' 3617db96d56Sopenharmony_ci return PyMethod.run(self) 3627db96d56Sopenharmony_ci 3637db96d56Sopenharmony_ci 3647db96d56Sopenharmony_ciclass PyCoroutineMixin(object): 3657db96d56Sopenharmony_ci def handle_signature(self, sig, signode): 3667db96d56Sopenharmony_ci ret = super(PyCoroutineMixin, self).handle_signature(sig, signode) 3677db96d56Sopenharmony_ci signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine ')) 3687db96d56Sopenharmony_ci return ret 3697db96d56Sopenharmony_ci 3707db96d56Sopenharmony_ci 3717db96d56Sopenharmony_ciclass PyAwaitableMixin(object): 3727db96d56Sopenharmony_ci def handle_signature(self, sig, signode): 3737db96d56Sopenharmony_ci ret = super(PyAwaitableMixin, self).handle_signature(sig, signode) 3747db96d56Sopenharmony_ci signode.insert(0, addnodes.desc_annotation('awaitable ', 'awaitable ')) 3757db96d56Sopenharmony_ci return ret 3767db96d56Sopenharmony_ci 3777db96d56Sopenharmony_ci 3787db96d56Sopenharmony_ciclass PyCoroutineFunction(PyCoroutineMixin, PyFunction): 3797db96d56Sopenharmony_ci def run(self): 3807db96d56Sopenharmony_ci self.name = 'py:function' 3817db96d56Sopenharmony_ci return PyFunction.run(self) 3827db96d56Sopenharmony_ci 3837db96d56Sopenharmony_ci 3847db96d56Sopenharmony_ciclass PyCoroutineMethod(PyCoroutineMixin, PyMethod): 3857db96d56Sopenharmony_ci def run(self): 3867db96d56Sopenharmony_ci self.name = 'py:method' 3877db96d56Sopenharmony_ci return PyMethod.run(self) 3887db96d56Sopenharmony_ci 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ciclass PyAwaitableFunction(PyAwaitableMixin, PyFunction): 3917db96d56Sopenharmony_ci def run(self): 3927db96d56Sopenharmony_ci self.name = 'py:function' 3937db96d56Sopenharmony_ci return PyFunction.run(self) 3947db96d56Sopenharmony_ci 3957db96d56Sopenharmony_ci 3967db96d56Sopenharmony_ciclass PyAwaitableMethod(PyAwaitableMixin, PyMethod): 3977db96d56Sopenharmony_ci def run(self): 3987db96d56Sopenharmony_ci self.name = 'py:method' 3997db96d56Sopenharmony_ci return PyMethod.run(self) 4007db96d56Sopenharmony_ci 4017db96d56Sopenharmony_ci 4027db96d56Sopenharmony_ciclass PyAbstractMethod(PyMethod): 4037db96d56Sopenharmony_ci 4047db96d56Sopenharmony_ci def handle_signature(self, sig, signode): 4057db96d56Sopenharmony_ci ret = super(PyAbstractMethod, self).handle_signature(sig, signode) 4067db96d56Sopenharmony_ci signode.insert(0, addnodes.desc_annotation('abstractmethod ', 4077db96d56Sopenharmony_ci 'abstractmethod ')) 4087db96d56Sopenharmony_ci return ret 4097db96d56Sopenharmony_ci 4107db96d56Sopenharmony_ci def run(self): 4117db96d56Sopenharmony_ci self.name = 'py:method' 4127db96d56Sopenharmony_ci return PyMethod.run(self) 4137db96d56Sopenharmony_ci 4147db96d56Sopenharmony_ci 4157db96d56Sopenharmony_ci# Support for documenting version of removal in deprecations 4167db96d56Sopenharmony_ci 4177db96d56Sopenharmony_ciclass DeprecatedRemoved(Directive): 4187db96d56Sopenharmony_ci has_content = True 4197db96d56Sopenharmony_ci required_arguments = 2 4207db96d56Sopenharmony_ci optional_arguments = 1 4217db96d56Sopenharmony_ci final_argument_whitespace = True 4227db96d56Sopenharmony_ci option_spec = {} 4237db96d56Sopenharmony_ci 4247db96d56Sopenharmony_ci _deprecated_label = 'Deprecated since version {deprecated}, will be removed in version {removed}' 4257db96d56Sopenharmony_ci _removed_label = 'Deprecated since version {deprecated}, removed in version {removed}' 4267db96d56Sopenharmony_ci 4277db96d56Sopenharmony_ci def run(self): 4287db96d56Sopenharmony_ci node = addnodes.versionmodified() 4297db96d56Sopenharmony_ci node.document = self.state.document 4307db96d56Sopenharmony_ci node['type'] = 'deprecated-removed' 4317db96d56Sopenharmony_ci version = (self.arguments[0], self.arguments[1]) 4327db96d56Sopenharmony_ci node['version'] = version 4337db96d56Sopenharmony_ci env = self.state.document.settings.env 4347db96d56Sopenharmony_ci current_version = tuple(int(e) for e in env.config.version.split('.')) 4357db96d56Sopenharmony_ci removed_version = tuple(int(e) for e in self.arguments[1].split('.')) 4367db96d56Sopenharmony_ci if current_version < removed_version: 4377db96d56Sopenharmony_ci label = self._deprecated_label 4387db96d56Sopenharmony_ci else: 4397db96d56Sopenharmony_ci label = self._removed_label 4407db96d56Sopenharmony_ci 4417db96d56Sopenharmony_ci label = sphinx_gettext(label) 4427db96d56Sopenharmony_ci text = label.format(deprecated=self.arguments[0], removed=self.arguments[1]) 4437db96d56Sopenharmony_ci if len(self.arguments) == 3: 4447db96d56Sopenharmony_ci inodes, messages = self.state.inline_text(self.arguments[2], 4457db96d56Sopenharmony_ci self.lineno+1) 4467db96d56Sopenharmony_ci para = nodes.paragraph(self.arguments[2], '', *inodes, translatable=False) 4477db96d56Sopenharmony_ci node.append(para) 4487db96d56Sopenharmony_ci else: 4497db96d56Sopenharmony_ci messages = [] 4507db96d56Sopenharmony_ci if self.content: 4517db96d56Sopenharmony_ci self.state.nested_parse(self.content, self.content_offset, node) 4527db96d56Sopenharmony_ci if len(node): 4537db96d56Sopenharmony_ci if isinstance(node[0], nodes.paragraph) and node[0].rawsource: 4547db96d56Sopenharmony_ci content = nodes.inline(node[0].rawsource, translatable=True) 4557db96d56Sopenharmony_ci content.source = node[0].source 4567db96d56Sopenharmony_ci content.line = node[0].line 4577db96d56Sopenharmony_ci content += node[0].children 4587db96d56Sopenharmony_ci node[0].replace_self(nodes.paragraph('', '', content, translatable=False)) 4597db96d56Sopenharmony_ci node[0].insert(0, nodes.inline('', '%s: ' % text, 4607db96d56Sopenharmony_ci classes=['versionmodified'])) 4617db96d56Sopenharmony_ci else: 4627db96d56Sopenharmony_ci para = nodes.paragraph('', '', 4637db96d56Sopenharmony_ci nodes.inline('', '%s.' % text, 4647db96d56Sopenharmony_ci classes=['versionmodified']), 4657db96d56Sopenharmony_ci translatable=False) 4667db96d56Sopenharmony_ci node.append(para) 4677db96d56Sopenharmony_ci env = self.state.document.settings.env 4687db96d56Sopenharmony_ci env.get_domain('changeset').note_changeset(node) 4697db96d56Sopenharmony_ci return [node] + messages 4707db96d56Sopenharmony_ci 4717db96d56Sopenharmony_ci 4727db96d56Sopenharmony_ci# Support for including Misc/NEWS 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_ciissue_re = re.compile('(?:[Ii]ssue #|bpo-)([0-9]+)', re.I) 4757db96d56Sopenharmony_cigh_issue_re = re.compile('(?:gh-issue-|gh-)([0-9]+)', re.I) 4767db96d56Sopenharmony_ciwhatsnew_re = re.compile(r"(?im)^what's new in (.*?)\??$") 4777db96d56Sopenharmony_ci 4787db96d56Sopenharmony_ci 4797db96d56Sopenharmony_ciclass MiscNews(Directive): 4807db96d56Sopenharmony_ci has_content = False 4817db96d56Sopenharmony_ci required_arguments = 1 4827db96d56Sopenharmony_ci optional_arguments = 0 4837db96d56Sopenharmony_ci final_argument_whitespace = False 4847db96d56Sopenharmony_ci option_spec = {} 4857db96d56Sopenharmony_ci 4867db96d56Sopenharmony_ci def run(self): 4877db96d56Sopenharmony_ci fname = self.arguments[0] 4887db96d56Sopenharmony_ci source = self.state_machine.input_lines.source( 4897db96d56Sopenharmony_ci self.lineno - self.state_machine.input_offset - 1) 4907db96d56Sopenharmony_ci source_dir = getenv('PY_MISC_NEWS_DIR') 4917db96d56Sopenharmony_ci if not source_dir: 4927db96d56Sopenharmony_ci source_dir = path.dirname(path.abspath(source)) 4937db96d56Sopenharmony_ci fpath = path.join(source_dir, fname) 4947db96d56Sopenharmony_ci self.state.document.settings.record_dependencies.add(fpath) 4957db96d56Sopenharmony_ci try: 4967db96d56Sopenharmony_ci with io.open(fpath, encoding='utf-8') as fp: 4977db96d56Sopenharmony_ci content = fp.read() 4987db96d56Sopenharmony_ci except Exception: 4997db96d56Sopenharmony_ci text = 'The NEWS file is not available.' 5007db96d56Sopenharmony_ci node = nodes.strong(text, text) 5017db96d56Sopenharmony_ci return [node] 5027db96d56Sopenharmony_ci content = issue_re.sub(r':issue:`\1`', content) 5037db96d56Sopenharmony_ci # Fallback handling for the GitHub issue 5047db96d56Sopenharmony_ci content = gh_issue_re.sub(r':gh:`\1`', content) 5057db96d56Sopenharmony_ci content = whatsnew_re.sub(r'\1', content) 5067db96d56Sopenharmony_ci # remove first 3 lines as they are the main heading 5077db96d56Sopenharmony_ci lines = ['.. default-role:: obj', ''] + content.splitlines()[3:] 5087db96d56Sopenharmony_ci self.state_machine.insert_input(lines, fname) 5097db96d56Sopenharmony_ci return [] 5107db96d56Sopenharmony_ci 5117db96d56Sopenharmony_ci 5127db96d56Sopenharmony_ci# Support for building "topic help" for pydoc 5137db96d56Sopenharmony_ci 5147db96d56Sopenharmony_cipydoc_topic_labels = [ 5157db96d56Sopenharmony_ci 'assert', 'assignment', 'async', 'atom-identifiers', 'atom-literals', 5167db96d56Sopenharmony_ci 'attribute-access', 'attribute-references', 'augassign', 'await', 5177db96d56Sopenharmony_ci 'binary', 'bitwise', 'bltin-code-objects', 'bltin-ellipsis-object', 5187db96d56Sopenharmony_ci 'bltin-null-object', 'bltin-type-objects', 'booleans', 5197db96d56Sopenharmony_ci 'break', 'callable-types', 'calls', 'class', 'comparisons', 'compound', 5207db96d56Sopenharmony_ci 'context-managers', 'continue', 'conversions', 'customization', 'debugger', 5217db96d56Sopenharmony_ci 'del', 'dict', 'dynamic-features', 'else', 'exceptions', 'execmodel', 5227db96d56Sopenharmony_ci 'exprlists', 'floating', 'for', 'formatstrings', 'function', 'global', 5237db96d56Sopenharmony_ci 'id-classes', 'identifiers', 'if', 'imaginary', 'import', 'in', 'integers', 5247db96d56Sopenharmony_ci 'lambda', 'lists', 'naming', 'nonlocal', 'numbers', 'numeric-types', 5257db96d56Sopenharmony_ci 'objects', 'operator-summary', 'pass', 'power', 'raise', 'return', 5267db96d56Sopenharmony_ci 'sequence-types', 'shifting', 'slicings', 'specialattrs', 'specialnames', 5277db96d56Sopenharmony_ci 'string-methods', 'strings', 'subscriptions', 'truth', 'try', 'types', 5287db96d56Sopenharmony_ci 'typesfunctions', 'typesmapping', 'typesmethods', 'typesmodules', 5297db96d56Sopenharmony_ci 'typesseq', 'typesseq-mutable', 'unary', 'while', 'with', 'yield' 5307db96d56Sopenharmony_ci] 5317db96d56Sopenharmony_ci 5327db96d56Sopenharmony_ci 5337db96d56Sopenharmony_ciclass PydocTopicsBuilder(Builder): 5347db96d56Sopenharmony_ci name = 'pydoc-topics' 5357db96d56Sopenharmony_ci 5367db96d56Sopenharmony_ci default_translator_class = TextTranslator 5377db96d56Sopenharmony_ci 5387db96d56Sopenharmony_ci def init(self): 5397db96d56Sopenharmony_ci self.topics = {} 5407db96d56Sopenharmony_ci self.secnumbers = {} 5417db96d56Sopenharmony_ci 5427db96d56Sopenharmony_ci def get_outdated_docs(self): 5437db96d56Sopenharmony_ci return 'all pydoc topics' 5447db96d56Sopenharmony_ci 5457db96d56Sopenharmony_ci def get_target_uri(self, docname, typ=None): 5467db96d56Sopenharmony_ci return '' # no URIs 5477db96d56Sopenharmony_ci 5487db96d56Sopenharmony_ci def write(self, *ignored): 5497db96d56Sopenharmony_ci writer = TextWriter(self) 5507db96d56Sopenharmony_ci for label in status_iterator(pydoc_topic_labels, 5517db96d56Sopenharmony_ci 'building topics... ', 5527db96d56Sopenharmony_ci length=len(pydoc_topic_labels)): 5537db96d56Sopenharmony_ci if label not in self.env.domaindata['std']['labels']: 5547db96d56Sopenharmony_ci self.env.logger.warn('label %r not in documentation' % label) 5557db96d56Sopenharmony_ci continue 5567db96d56Sopenharmony_ci docname, labelid, sectname = self.env.domaindata['std']['labels'][label] 5577db96d56Sopenharmony_ci doctree = self.env.get_and_resolve_doctree(docname, self) 5587db96d56Sopenharmony_ci document = new_document('<section node>') 5597db96d56Sopenharmony_ci document.append(doctree.ids[labelid]) 5607db96d56Sopenharmony_ci destination = StringOutput(encoding='utf-8') 5617db96d56Sopenharmony_ci writer.write(document, destination) 5627db96d56Sopenharmony_ci self.topics[label] = writer.output 5637db96d56Sopenharmony_ci 5647db96d56Sopenharmony_ci def finish(self): 5657db96d56Sopenharmony_ci f = open(path.join(self.outdir, 'topics.py'), 'wb') 5667db96d56Sopenharmony_ci try: 5677db96d56Sopenharmony_ci f.write('# -*- coding: utf-8 -*-\n'.encode('utf-8')) 5687db96d56Sopenharmony_ci f.write(('# Autogenerated by Sphinx on %s\n' % asctime()).encode('utf-8')) 5697db96d56Sopenharmony_ci f.write(('topics = ' + pformat(self.topics) + '\n').encode('utf-8')) 5707db96d56Sopenharmony_ci finally: 5717db96d56Sopenharmony_ci f.close() 5727db96d56Sopenharmony_ci 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci# Support for documenting Opcodes 5757db96d56Sopenharmony_ci 5767db96d56Sopenharmony_ciopcode_sig_re = re.compile(r'(\w+(?:\+\d)?)(?:\s*\((.*)\))?') 5777db96d56Sopenharmony_ci 5787db96d56Sopenharmony_ci 5797db96d56Sopenharmony_cidef parse_opcode_signature(env, sig, signode): 5807db96d56Sopenharmony_ci """Transform an opcode signature into RST nodes.""" 5817db96d56Sopenharmony_ci m = opcode_sig_re.match(sig) 5827db96d56Sopenharmony_ci if m is None: 5837db96d56Sopenharmony_ci raise ValueError 5847db96d56Sopenharmony_ci opname, arglist = m.groups() 5857db96d56Sopenharmony_ci signode += addnodes.desc_name(opname, opname) 5867db96d56Sopenharmony_ci if arglist is not None: 5877db96d56Sopenharmony_ci paramlist = addnodes.desc_parameterlist() 5887db96d56Sopenharmony_ci signode += paramlist 5897db96d56Sopenharmony_ci paramlist += addnodes.desc_parameter(arglist, arglist) 5907db96d56Sopenharmony_ci return opname.strip() 5917db96d56Sopenharmony_ci 5927db96d56Sopenharmony_ci 5937db96d56Sopenharmony_ci# Support for documenting pdb commands 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_cipdbcmd_sig_re = re.compile(r'([a-z()!]+)\s*(.*)') 5967db96d56Sopenharmony_ci 5977db96d56Sopenharmony_ci# later... 5987db96d56Sopenharmony_ci# pdbargs_tokens_re = re.compile(r'''[a-zA-Z]+ | # identifiers 5997db96d56Sopenharmony_ci# [.,:]+ | # punctuation 6007db96d56Sopenharmony_ci# [\[\]()] | # parens 6017db96d56Sopenharmony_ci# \s+ # whitespace 6027db96d56Sopenharmony_ci# ''', re.X) 6037db96d56Sopenharmony_ci 6047db96d56Sopenharmony_ci 6057db96d56Sopenharmony_cidef parse_pdb_command(env, sig, signode): 6067db96d56Sopenharmony_ci """Transform a pdb command signature into RST nodes.""" 6077db96d56Sopenharmony_ci m = pdbcmd_sig_re.match(sig) 6087db96d56Sopenharmony_ci if m is None: 6097db96d56Sopenharmony_ci raise ValueError 6107db96d56Sopenharmony_ci name, args = m.groups() 6117db96d56Sopenharmony_ci fullname = name.replace('(', '').replace(')', '') 6127db96d56Sopenharmony_ci signode += addnodes.desc_name(name, name) 6137db96d56Sopenharmony_ci if args: 6147db96d56Sopenharmony_ci signode += addnodes.desc_addname(' '+args, ' '+args) 6157db96d56Sopenharmony_ci return fullname 6167db96d56Sopenharmony_ci 6177db96d56Sopenharmony_ci 6187db96d56Sopenharmony_cidef process_audit_events(app, doctree, fromdocname): 6197db96d56Sopenharmony_ci for node in doctree.traverse(audit_event_list): 6207db96d56Sopenharmony_ci break 6217db96d56Sopenharmony_ci else: 6227db96d56Sopenharmony_ci return 6237db96d56Sopenharmony_ci 6247db96d56Sopenharmony_ci env = app.builder.env 6257db96d56Sopenharmony_ci 6267db96d56Sopenharmony_ci table = nodes.table(cols=3) 6277db96d56Sopenharmony_ci group = nodes.tgroup( 6287db96d56Sopenharmony_ci '', 6297db96d56Sopenharmony_ci nodes.colspec(colwidth=30), 6307db96d56Sopenharmony_ci nodes.colspec(colwidth=55), 6317db96d56Sopenharmony_ci nodes.colspec(colwidth=15), 6327db96d56Sopenharmony_ci cols=3, 6337db96d56Sopenharmony_ci ) 6347db96d56Sopenharmony_ci head = nodes.thead() 6357db96d56Sopenharmony_ci body = nodes.tbody() 6367db96d56Sopenharmony_ci 6377db96d56Sopenharmony_ci table += group 6387db96d56Sopenharmony_ci group += head 6397db96d56Sopenharmony_ci group += body 6407db96d56Sopenharmony_ci 6417db96d56Sopenharmony_ci row = nodes.row() 6427db96d56Sopenharmony_ci row += nodes.entry('', nodes.paragraph('', nodes.Text('Audit event'))) 6437db96d56Sopenharmony_ci row += nodes.entry('', nodes.paragraph('', nodes.Text('Arguments'))) 6447db96d56Sopenharmony_ci row += nodes.entry('', nodes.paragraph('', nodes.Text('References'))) 6457db96d56Sopenharmony_ci head += row 6467db96d56Sopenharmony_ci 6477db96d56Sopenharmony_ci for name in sorted(getattr(env, "all_audit_events", ())): 6487db96d56Sopenharmony_ci audit_event = env.all_audit_events[name] 6497db96d56Sopenharmony_ci 6507db96d56Sopenharmony_ci row = nodes.row() 6517db96d56Sopenharmony_ci node = nodes.paragraph('', nodes.Text(name)) 6527db96d56Sopenharmony_ci row += nodes.entry('', node) 6537db96d56Sopenharmony_ci 6547db96d56Sopenharmony_ci node = nodes.paragraph() 6557db96d56Sopenharmony_ci for i, a in enumerate(audit_event['args']): 6567db96d56Sopenharmony_ci if i: 6577db96d56Sopenharmony_ci node += nodes.Text(", ") 6587db96d56Sopenharmony_ci node += nodes.literal(a, nodes.Text(a)) 6597db96d56Sopenharmony_ci row += nodes.entry('', node) 6607db96d56Sopenharmony_ci 6617db96d56Sopenharmony_ci node = nodes.paragraph() 6627db96d56Sopenharmony_ci backlinks = enumerate(sorted(set(audit_event['source'])), start=1) 6637db96d56Sopenharmony_ci for i, (doc, label) in backlinks: 6647db96d56Sopenharmony_ci if isinstance(label, str): 6657db96d56Sopenharmony_ci ref = nodes.reference("", nodes.Text("[{}]".format(i)), internal=True) 6667db96d56Sopenharmony_ci try: 6677db96d56Sopenharmony_ci ref['refuri'] = "{}#{}".format( 6687db96d56Sopenharmony_ci app.builder.get_relative_uri(fromdocname, doc), 6697db96d56Sopenharmony_ci label, 6707db96d56Sopenharmony_ci ) 6717db96d56Sopenharmony_ci except NoUri: 6727db96d56Sopenharmony_ci continue 6737db96d56Sopenharmony_ci node += ref 6747db96d56Sopenharmony_ci row += nodes.entry('', node) 6757db96d56Sopenharmony_ci 6767db96d56Sopenharmony_ci body += row 6777db96d56Sopenharmony_ci 6787db96d56Sopenharmony_ci for node in doctree.traverse(audit_event_list): 6797db96d56Sopenharmony_ci node.replace_self(table) 6807db96d56Sopenharmony_ci 6817db96d56Sopenharmony_ci 6827db96d56Sopenharmony_cidef patch_pairindextypes(app, _env) -> None: 6837db96d56Sopenharmony_ci """Remove all entries from ``pairindextypes`` before writing POT files. 6847db96d56Sopenharmony_ci 6857db96d56Sopenharmony_ci We want to run this just before writing output files, as the check to 6867db96d56Sopenharmony_ci circumvent is in ``I18nBuilder.write_doc()``. 6877db96d56Sopenharmony_ci As such, we link this to ``env-check-consistency``, even though it has 6887db96d56Sopenharmony_ci nothing to do with the environment consistency check. 6897db96d56Sopenharmony_ci """ 6907db96d56Sopenharmony_ci if app.builder.name != 'gettext': 6917db96d56Sopenharmony_ci return 6927db96d56Sopenharmony_ci 6937db96d56Sopenharmony_ci # allow translating deprecated index entries 6947db96d56Sopenharmony_ci try: 6957db96d56Sopenharmony_ci from sphinx.domains.python import pairindextypes 6967db96d56Sopenharmony_ci except ImportError: 6977db96d56Sopenharmony_ci pass 6987db96d56Sopenharmony_ci else: 6997db96d56Sopenharmony_ci # Sphinx checks if a 'pair' type entry on an index directive is one of 7007db96d56Sopenharmony_ci # the Sphinx-translated pairindextypes values. As we intend to move 7017db96d56Sopenharmony_ci # away from this, we need Sphinx to believe that these values don't 7027db96d56Sopenharmony_ci # exist, by deleting them when using the gettext builder. 7037db96d56Sopenharmony_ci pairindextypes.clear() 7047db96d56Sopenharmony_ci 7057db96d56Sopenharmony_ci 7067db96d56Sopenharmony_cidef setup(app): 7077db96d56Sopenharmony_ci app.add_role('issue', issue_role) 7087db96d56Sopenharmony_ci app.add_role('gh', gh_issue_role) 7097db96d56Sopenharmony_ci app.add_role('source', source_role) 7107db96d56Sopenharmony_ci app.add_directive('impl-detail', ImplementationDetail) 7117db96d56Sopenharmony_ci app.add_directive('availability', Availability) 7127db96d56Sopenharmony_ci app.add_directive('audit-event', AuditEvent) 7137db96d56Sopenharmony_ci app.add_directive('audit-event-table', AuditEventListDirective) 7147db96d56Sopenharmony_ci app.add_directive('deprecated-removed', DeprecatedRemoved) 7157db96d56Sopenharmony_ci app.add_builder(PydocTopicsBuilder) 7167db96d56Sopenharmony_ci app.add_builder(suspicious.CheckSuspiciousMarkupBuilder) 7177db96d56Sopenharmony_ci app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) 7187db96d56Sopenharmony_ci app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command) 7197db96d56Sopenharmony_ci app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)') 7207db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction) 7217db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod) 7227db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction) 7237db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'coroutinemethod', PyCoroutineMethod) 7247db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'awaitablefunction', PyAwaitableFunction) 7257db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) 7267db96d56Sopenharmony_ci app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod) 7277db96d56Sopenharmony_ci app.add_directive('miscnews', MiscNews) 7287db96d56Sopenharmony_ci app.connect('env-check-consistency', patch_pairindextypes) 7297db96d56Sopenharmony_ci app.connect('doctree-resolved', process_audit_events) 7307db96d56Sopenharmony_ci app.connect('env-merge-info', audit_events_merge) 7317db96d56Sopenharmony_ci app.connect('env-purge-doc', audit_events_purge) 7327db96d56Sopenharmony_ci return {'version': '1.0', 'parallel_read_safe': True} 733