From nobody Sat Nov 15 19:07:36 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1747933415; cv=none; d=zohomail.com; s=zohoarc; b=AEiReshlTt0a31EIxzOO3iK7rMmM4AFdbvtzjAGqmEg+ajpa6eugWI97AodxzIqTsy+U+OhY3mm/DwptRKwOa0LJ4yKOtYGwHzNSHop1q8do9OvHtm6le2DuwsQMVidufViWkA2zR3r7tqB4XahyTohUTJ957ho3Bo4ygmAoaC8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1747933415; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=YwYWDWWYNd5Sp/FfY6A1ctBd21KhnWBm7Q2Ym9eiLRQ=; b=hXTR9CUNWGN5lyXAGIlN2YDuguasAnMr6Nzxe9lQQYXZ/yYJyfCUmgPLEvds7NCqCncGQ4qFTz5xLBfTP+HV/MMfcmr5OOVVnFoysDZQUtfpd6D0CJ8+SftHnYKmb+Z+pLUOoye/l4j7jzxN5yIbhRxcOoUMCQ33yxDWTezY/sE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1747933415729877.6870287408766; Thu, 22 May 2025 10:03:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uI9Jz-0003gf-1B; Thu, 22 May 2025 13:03:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uI9Jq-0003fS-0X for qemu-devel@nongnu.org; Thu, 22 May 2025 13:03:01 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uI9Jo-00086x-7L for qemu-devel@nongnu.org; Thu, 22 May 2025 13:02:57 -0400 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-167-LAZ-nDIWPvyX7_jZMyVKRw-1; Thu, 22 May 2025 13:02:49 -0400 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 95994180036F; Thu, 22 May 2025 17:02:45 +0000 (UTC) Received: from jsnow-thinkpadp16vgen1.westford.csb (unknown [10.22.64.178]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 901C619560AD; Thu, 22 May 2025 17:02:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1747933374; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YwYWDWWYNd5Sp/FfY6A1ctBd21KhnWBm7Q2Ym9eiLRQ=; b=WGUOnMKH4WvAvPGDrFWMpOKrtYlYAv0JsSvsvyOxcrl07xNSs6GHi0oDXD0Jgas83Do+Li 26pf4o8tFHxOl2f9G3QCV9zVa1zpdz4un4qjHaVts7R4Ka7XIypUa7W7i1taC02tBAXfOS GTV0JpXPuibFOx6nYIL2hgFYdqTx6d8= X-MC-Unique: LAZ-nDIWPvyX7_jZMyVKRw-1 X-Mimecast-MFC-AGG-ID: LAZ-nDIWPvyX7_jZMyVKRw_1747933366 From: John Snow To: qemu-devel@nongnu.org Cc: Fan Ni , Zhao Liu , Kashyap Chamarthy , "Michael S. Tsirkin" , Vladimir Sementsov-Ogievskiy , qemu-block@nongnu.org, Marcel Apfelbaum , Jonathan Cameron , Ani Sinha , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Zhenwei Pi , Jason Wang , Peter Maydell , Fabiano Rosas , Paolo Bonzini , Alex Williamson , Stefan Hajnoczi , John Snow , Hanna Reitz , Jiri Pirko , Igor Mammedov , "Gonglei (Arei)" , Eric Blake , Gerd Hoffmann , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Michael Roth , Yanan Wang , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Lukas Straub , Stefano Garzarella , Stefan Berger , Mads Ynddal , Konstantin Kostiuk , Peter Xu , Eduardo Habkost , Kevin Wolf , Markus Armbruster , Cleber Rosa , =?UTF-8?q?Alex=20Benn=C3=A9e?= Subject: [PATCH 1/3] docs: fix errors formatting in test-good Date: Thu, 22 May 2025 13:02:17 -0400 Message-ID: <20250522170219.58058-2-jsnow@redhat.com> In-Reply-To: <20250522170219.58058-1-jsnow@redhat.com> References: <20250522170219.58058-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -23 X-Spam_score: -2.4 X-Spam_bar: -- X-Spam_report: (-2.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.275, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1747933418544116601 Content-Type: text/plain; charset="utf-8" If we remove the legacy parser, this formulation begins to fail because the body text is appended directly after the field list entry, which is invalid rST syntax. Markus: suggest where the new Exception(s) should go, if anywhere, and how to update the tests? I'm assuming deeply you'll want to. Signed-off-by: John Snow --- tests/qapi-schema/doc-good.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.j= son index 14b808f9090..6dcde8fd7e8 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -165,7 +165,8 @@ # # Returns: @Object # -# Errors: some +# Errors: +# - some # # TODO: frobnicate # --=20 2.48.1 From nobody Sat Nov 15 19:07:36 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1747933491; cv=none; d=zohomail.com; s=zohoarc; b=keM7wtKUOfkvQ8PEPHmJZgZ/6aMIVRN60XS2o7iNyg3Dxl3Tk9rWkxZGW+EoPq1YvGBS+UxgY/A4tGWgf3H/zP7PExCCuY6sYjsQWFgYAaakdrA51yL/Pmc3k1PAupYKdx909drch4gSnYc3fokzu/xEwS6BhCNOcKtTNP9wKdg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1747933491; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=flXxQ9mQ75rzpuGxgTAIi78ZPPtvSQUgnaAAbPBO+xw=; b=f//Y68tkYjNP6n8xzTC69maj49kDT8EdcOvgk91YTVEeFZcwEdgDtma+2IJMjJKWZHcF2sBTUu0PYgjtppTEEunnyL9+TZI2Nld/4dzcQ4q9N40GcEFdKYtsvzaS7IBQukpb4/yhQJoPIXxEWNnYAq7FOZ8L1dgEo49J5Ft71iA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1747933491510269.46725912597196; Thu, 22 May 2025 10:04:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uI9K7-0003iu-1C; Thu, 22 May 2025 13:03:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uI9K1-0003hh-56 for qemu-devel@nongnu.org; Thu, 22 May 2025 13:03:09 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uI9Jx-00088A-Sp for qemu-devel@nongnu.org; Thu, 22 May 2025 13:03:08 -0400 Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-378-yid41W9qPz26hS4C8Jjy6A-1; Thu, 22 May 2025 13:03:01 -0400 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CD68B1800261; Thu, 22 May 2025 17:02:57 +0000 (UTC) Received: from jsnow-thinkpadp16vgen1.westford.csb (unknown [10.22.64.178]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1088B195608F; Thu, 22 May 2025 17:02:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1747933384; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=flXxQ9mQ75rzpuGxgTAIi78ZPPtvSQUgnaAAbPBO+xw=; b=cE0zwtHeCdEqj5F9001P1u5B+qhvFtAHXVb7ct38swPpio3OHvuyJH/Fx5gsw0/JwRl6Gn 9GVJ92XV1yN5iqZd9TSpliP4htYEdN0wj+4zmMUdVy+jK5AO7RpMZukC0TxAkcIL7nqlWV +lNSRqxcf71fkjMMXb7w2jW3rqPU6Gw= X-MC-Unique: yid41W9qPz26hS4C8Jjy6A-1 X-Mimecast-MFC-AGG-ID: yid41W9qPz26hS4C8Jjy6A_1747933378 From: John Snow To: qemu-devel@nongnu.org Cc: Fan Ni , Zhao Liu , Kashyap Chamarthy , "Michael S. Tsirkin" , Vladimir Sementsov-Ogievskiy , qemu-block@nongnu.org, Marcel Apfelbaum , Jonathan Cameron , Ani Sinha , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Zhenwei Pi , Jason Wang , Peter Maydell , Fabiano Rosas , Paolo Bonzini , Alex Williamson , Stefan Hajnoczi , John Snow , Hanna Reitz , Jiri Pirko , Igor Mammedov , "Gonglei (Arei)" , Eric Blake , Gerd Hoffmann , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Michael Roth , Yanan Wang , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Lukas Straub , Stefano Garzarella , Stefan Berger , Mads Ynddal , Konstantin Kostiuk , Peter Xu , Eduardo Habkost , Kevin Wolf , Markus Armbruster , Cleber Rosa , =?UTF-8?q?Alex=20Benn=C3=A9e?= Subject: [PATCH 2/3] docs: remove legacy QAPI manual generator Date: Thu, 22 May 2025 13:02:18 -0400 Message-ID: <20250522170219.58058-3-jsnow@redhat.com> In-Reply-To: <20250522170219.58058-1-jsnow@redhat.com> References: <20250522170219.58058-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -23 X-Spam_score: -2.4 X-Spam_bar: -- X-Spam_report: (-2.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.275, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1747933493536116600 Content-Type: text/plain; charset="utf-8" Thanks for your service! Remove the old qapidoc and the option to enable the transmogrifier, leaving the transmogrifier as the ONLY qapi doc generator. This has the side effect of converting the tests to use the new system, too. Signed-off-by: John Snow --- docs/interop/qemu-ga-ref.rst | 1 - docs/interop/qemu-qmp-ref.rst | 1 - docs/interop/qemu-storage-daemon-qmp-ref.rst | 1 - docs/sphinx/qapidoc.py | 25 +- docs/sphinx/qapidoc_legacy.py | 440 ------------------- python/tests/qapi-isort.sh | 2 +- 6 files changed, 2 insertions(+), 468 deletions(-) delete mode 100644 docs/sphinx/qapidoc_legacy.py diff --git a/docs/interop/qemu-ga-ref.rst b/docs/interop/qemu-ga-ref.rst index 25f6e24b03c..ea6652ae43e 100644 --- a/docs/interop/qemu-ga-ref.rst +++ b/docs/interop/qemu-ga-ref.rst @@ -2,5 +2,4 @@ QEMU Guest Agent Protocol Reference =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 .. qapi-doc:: qga/qapi-schema.json - :transmogrify: :namespace: QGA diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst index 3bc1ca12b16..f0ce39ad67d 100644 --- a/docs/interop/qemu-qmp-ref.rst +++ b/docs/interop/qemu-qmp-ref.rst @@ -7,5 +7,4 @@ QEMU QMP Reference Manual :local: =20 .. qapi-doc:: qapi/qapi-schema.json - :transmogrify: :namespace: QMP diff --git a/docs/interop/qemu-storage-daemon-qmp-ref.rst b/docs/interop/qe= mu-storage-daemon-qmp-ref.rst index dc7bde262ae..4dbb6a2cc83 100644 --- a/docs/interop/qemu-storage-daemon-qmp-ref.rst +++ b/docs/interop/qemu-storage-daemon-qmp-ref.rst @@ -5,5 +5,4 @@ QEMU Storage Daemon QMP Reference Manual :local: =20 .. qapi-doc:: storage-daemon/qapi/qapi-schema.json - :transmogrify: :namespace: QSD diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py index 8011ac9efaf..c9c477378f5 100644 --- a/docs/sphinx/qapidoc.py +++ b/docs/sphinx/qapidoc.py @@ -64,8 +64,6 @@ from sphinx.util.docutils import SphinxDirective, switch_source_input from sphinx.util.nodes import nested_parse_with_titles =20 -from qapidoc_legacy import QAPISchemaGenRSTVisitor # type: ignore - =20 if TYPE_CHECKING: from typing import ( @@ -504,15 +502,9 @@ class QAPIDocDirective(NestedDirective): option_spec =3D { "qapifile": directives.unchanged_required, "namespace": directives.unchanged, - "transmogrify": directives.flag, } has_content =3D False =20 - def new_serialno(self) -> str: - """Return a unique new ID string suitable for use as a node's ID""" - env =3D self.state.document.settings.env - return "qapidoc-%d" % env.new_serialno("qapidoc") - def transmogrify(self, schema: QAPISchema) -> nodes.Element: logger.info("Transmogrifying QAPI to rST ...") vis =3D Transmogrifier() @@ -590,21 +582,10 @@ def write_intermediate(self, content: StringList, fil= ename: str) -> None: outfile.write(f" {rcol}") outfile.write("\n") =20 - def legacy(self, schema: QAPISchema) -> nodes.Element: - vis =3D QAPISchemaGenRSTVisitor(self) - vis.visit_begin(schema) - for doc in schema.docs: - if doc.symbol: - vis.symbol(doc, schema.lookup_entity(doc.symbol)) - else: - vis.freeform(doc) - return vis.get_document_node() # type: ignore - def run(self) -> Sequence[nodes.Node]: env =3D self.state.document.settings.env qapifile =3D env.config.qapidoc_srctree + "/" + self.arguments[0] qapidir =3D os.path.dirname(qapifile) - transmogrify =3D "transmogrify" in self.options =20 try: schema =3D QAPISchema(qapifile) @@ -617,11 +598,7 @@ def run(self) -> Sequence[nodes.Node]: # so they are displayed nicely to the user raise ExtensionError(str(err)) from err =20 - if transmogrify: - contentnode =3D self.transmogrify(schema) - else: - contentnode =3D self.legacy(schema) - + contentnode =3D self.transmogrify(schema) return contentnode.children =20 =20 diff --git a/docs/sphinx/qapidoc_legacy.py b/docs/sphinx/qapidoc_legacy.py deleted file mode 100644 index 13520f4c26b..00000000000 --- a/docs/sphinx/qapidoc_legacy.py +++ /dev/null @@ -1,440 +0,0 @@ -# coding=3Dutf-8 -# type: ignore -# -# QEMU qapidoc QAPI file parsing extension -# -# Copyright (c) 2020 Linaro -# -# This work is licensed under the terms of the GNU GPLv2 or later. -# See the COPYING file in the top-level directory. - -""" -qapidoc is a Sphinx extension that implements the qapi-doc directive - -The purpose of this extension is to read the documentation comments -in QAPI schema files, and insert them all into the current document. - -It implements one new rST directive, "qapi-doc::". -Each qapi-doc:: directive takes one argument, which is the -pathname of the schema file to process, relative to the source tree. - -The docs/conf.py file must set the qapidoc_srctree config value to -the root of the QEMU source tree. - -The Sphinx documentation on writing extensions is at: -https://www.sphinx-doc.org/en/master/development/index.html -""" - -import re -import textwrap - -from docutils import nodes -from docutils.statemachine import ViewList -from qapi.error import QAPISemError -from qapi.gen import QAPISchemaVisitor -from qapi.parser import QAPIDoc - - -def dedent(text: str) -> str: - # Adjust indentation to make description text parse as paragraph. - - lines =3D text.splitlines(True) - if re.match(r"\s+", lines[0]): - # First line is indented; description started on the line after - # the name. dedent the whole block. - return textwrap.dedent(text) - - # Descr started on same line. Dedent line 2+. - return lines[0] + textwrap.dedent("".join(lines[1:])) - - -class QAPISchemaGenRSTVisitor(QAPISchemaVisitor): - """A QAPI schema visitor which generates docutils/Sphinx nodes - - This class builds up a tree of docutils/Sphinx nodes corresponding - to documentation for the various QAPI objects. To use it, first - create a QAPISchemaGenRSTVisitor object, and call its - visit_begin() method. Then you can call one of the two methods - 'freeform' (to add documentation for a freeform documentation - chunk) or 'symbol' (to add documentation for a QAPI symbol). These - will cause the visitor to build up the tree of document - nodes. Once you've added all the documentation via 'freeform' and - 'symbol' method calls, you can call 'get_document_nodes' to get - the final list of document nodes (in a form suitable for returning - from a Sphinx directive's 'run' method). - """ - def __init__(self, sphinx_directive): - self._cur_doc =3D None - self._sphinx_directive =3D sphinx_directive - self._top_node =3D nodes.section() - self._active_headings =3D [self._top_node] - - def _make_dlitem(self, term, defn): - """Return a dlitem node with the specified term and definition. - - term should be a list of Text and literal nodes. - defn should be one of: - - a string, which will be handed to _parse_text_into_node - - a list of Text and literal nodes, which will be put into - a paragraph node - """ - dlitem =3D nodes.definition_list_item() - dlterm =3D nodes.term('', '', *term) - dlitem +=3D dlterm - if defn: - dldef =3D nodes.definition() - if isinstance(defn, list): - dldef +=3D nodes.paragraph('', '', *defn) - else: - self._parse_text_into_node(defn, dldef) - dlitem +=3D dldef - return dlitem - - def _make_section(self, title): - """Return a section node with optional title""" - section =3D nodes.section(ids=3D[self._sphinx_directive.new_serial= no()]) - if title: - section +=3D nodes.title(title, title) - return section - - def _nodes_for_ifcond(self, ifcond, with_if=3DTrue): - """Return list of Text, literal nodes for the ifcond - - Return a list which gives text like ' (If: condition)'. - If with_if is False, we don't return the "(If: " and ")". - """ - - doc =3D ifcond.docgen() - if not doc: - return [] - doc =3D nodes.literal('', doc) - if not with_if: - return [doc] - - nodelist =3D [nodes.Text(' ('), nodes.strong('', 'If: ')] - nodelist.append(doc) - nodelist.append(nodes.Text(')')) - return nodelist - - def _nodes_for_one_member(self, member): - """Return list of Text, literal nodes for this member - - Return a list of doctree nodes which give text like - 'name: type (optional) (If: ...)' suitable for use as the - 'term' part of a definition list item. - """ - term =3D [nodes.literal('', member.name)] - if member.type.doc_type(): - term.append(nodes.Text(': ')) - term.append(nodes.literal('', member.type.doc_type())) - if member.optional: - term.append(nodes.Text(' (optional)')) - if member.ifcond.is_present(): - term.extend(self._nodes_for_ifcond(member.ifcond)) - return term - - def _nodes_for_variant_when(self, branches, variant): - """Return list of Text, literal nodes for variant 'when' clause - - Return a list of doctree nodes which give text like - 'when tagname is variant (If: ...)' suitable for use in - the 'branches' part of a definition list. - """ - term =3D [nodes.Text(' when '), - nodes.literal('', branches.tag_member.name), - nodes.Text(' is '), - nodes.literal('', '"%s"' % variant.name)] - if variant.ifcond.is_present(): - term.extend(self._nodes_for_ifcond(variant.ifcond)) - return term - - def _nodes_for_members(self, doc, what, base=3DNone, branches=3DNone): - """Return list of doctree nodes for the table of members""" - dlnode =3D nodes.definition_list() - for section in doc.args.values(): - term =3D self._nodes_for_one_member(section.member) - # TODO drop fallbacks when undocumented members are outlawed - if section.text: - defn =3D dedent(section.text) - else: - defn =3D [nodes.Text('Not documented')] - - dlnode +=3D self._make_dlitem(term, defn) - - if base: - dlnode +=3D self._make_dlitem([nodes.Text('The members of '), - nodes.literal('', base.doc_type()= )], - None) - - if branches: - for v in branches.variants: - if v.type.name =3D=3D 'q_empty': - continue - assert not v.type.is_implicit() - term =3D [nodes.Text('The members of '), - nodes.literal('', v.type.doc_type())] - term.extend(self._nodes_for_variant_when(branches, v)) - dlnode +=3D self._make_dlitem(term, None) - - if not dlnode.children: - return [] - - section =3D self._make_section(what) - section +=3D dlnode - return [section] - - def _nodes_for_enum_values(self, doc): - """Return list of doctree nodes for the table of enum values""" - seen_item =3D False - dlnode =3D nodes.definition_list() - for section in doc.args.values(): - termtext =3D [nodes.literal('', section.member.name)] - if section.member.ifcond.is_present(): - termtext.extend(self._nodes_for_ifcond(section.member.ifco= nd)) - # TODO drop fallbacks when undocumented members are outlawed - if section.text: - defn =3D dedent(section.text) - else: - defn =3D [nodes.Text('Not documented')] - - dlnode +=3D self._make_dlitem(termtext, defn) - seen_item =3D True - - if not seen_item: - return [] - - section =3D self._make_section('Values') - section +=3D dlnode - return [section] - - def _nodes_for_arguments(self, doc, arg_type): - """Return list of doctree nodes for the arguments section""" - if arg_type and not arg_type.is_implicit(): - assert not doc.args - section =3D self._make_section('Arguments') - dlnode =3D nodes.definition_list() - dlnode +=3D self._make_dlitem( - [nodes.Text('The members of '), - nodes.literal('', arg_type.name)], - None) - section +=3D dlnode - return [section] - - return self._nodes_for_members(doc, 'Arguments') - - def _nodes_for_features(self, doc): - """Return list of doctree nodes for the table of features""" - seen_item =3D False - dlnode =3D nodes.definition_list() - for section in doc.features.values(): - dlnode +=3D self._make_dlitem( - [nodes.literal('', section.member.name)], dedent(section.t= ext)) - seen_item =3D True - - if not seen_item: - return [] - - section =3D self._make_section('Features') - section +=3D dlnode - return [section] - - def _nodes_for_sections(self, doc): - """Return list of doctree nodes for additional sections""" - nodelist =3D [] - for section in doc.sections: - if section.kind =3D=3D QAPIDoc.Kind.TODO: - # Hide TODO: sections - continue - - if section.kind =3D=3D QAPIDoc.Kind.PLAIN: - # Sphinx cannot handle sectionless titles; - # Instead, just append the results to the prior section. - container =3D nodes.container() - self._parse_text_into_node(section.text, container) - nodelist +=3D container.children - continue - - snode =3D self._make_section(section.kind.name.title()) - self._parse_text_into_node(dedent(section.text), snode) - nodelist.append(snode) - return nodelist - - def _nodes_for_if_section(self, ifcond): - """Return list of doctree nodes for the "If" section""" - nodelist =3D [] - if ifcond.is_present(): - snode =3D self._make_section('If') - snode +=3D nodes.paragraph( - '', '', *self._nodes_for_ifcond(ifcond, with_if=3DFalse) - ) - nodelist.append(snode) - return nodelist - - def _add_doc(self, typ, sections): - """Add documentation for a command/object/enum... - - We assume we're documenting the thing defined in self._cur_doc. - typ is the type of thing being added ("Command", "Object", etc) - - sections is a list of nodes for sections to add to the definition. - """ - - doc =3D self._cur_doc - snode =3D nodes.section(ids=3D[self._sphinx_directive.new_serialno= ()]) - snode +=3D nodes.title('', '', *[nodes.literal(doc.symbol, doc.sym= bol), - nodes.Text(' (' + typ + ')')]) - self._parse_text_into_node(doc.body.text, snode) - for s in sections: - if s is not None: - snode +=3D s - self._add_node_to_current_heading(snode) - - def visit_enum_type(self, name, info, ifcond, features, members, prefi= x): - doc =3D self._cur_doc - self._add_doc('Enum', - self._nodes_for_enum_values(doc) - + self._nodes_for_features(doc) - + self._nodes_for_sections(doc) - + self._nodes_for_if_section(ifcond)) - - def visit_object_type(self, name, info, ifcond, features, - base, members, branches): - doc =3D self._cur_doc - if base and base.is_implicit(): - base =3D None - self._add_doc('Object', - self._nodes_for_members(doc, 'Members', base, branch= es) - + self._nodes_for_features(doc) - + self._nodes_for_sections(doc) - + self._nodes_for_if_section(ifcond)) - - def visit_alternate_type(self, name, info, ifcond, features, - alternatives): - doc =3D self._cur_doc - self._add_doc('Alternate', - self._nodes_for_members(doc, 'Members') - + self._nodes_for_features(doc) - + self._nodes_for_sections(doc) - + self._nodes_for_if_section(ifcond)) - - def visit_command(self, name, info, ifcond, features, arg_type, - ret_type, gen, success_response, boxed, allow_oob, - allow_preconfig, coroutine): - doc =3D self._cur_doc - self._add_doc('Command', - self._nodes_for_arguments(doc, arg_type) - + self._nodes_for_features(doc) - + self._nodes_for_sections(doc) - + self._nodes_for_if_section(ifcond)) - - def visit_event(self, name, info, ifcond, features, arg_type, boxed): - doc =3D self._cur_doc - self._add_doc('Event', - self._nodes_for_arguments(doc, arg_type) - + self._nodes_for_features(doc) - + self._nodes_for_sections(doc) - + self._nodes_for_if_section(ifcond)) - - def symbol(self, doc, entity): - """Add documentation for one symbol to the document tree - - This is the main entry point which causes us to add documentation - nodes for a symbol (which could be a 'command', 'object', 'event', - etc). We do this by calling 'visit' on the schema entity, which - will then call back into one of our visit_* methods, depending - on what kind of thing this symbol is. - """ - self._cur_doc =3D doc - entity.visit(self) - self._cur_doc =3D None - - def _start_new_heading(self, heading, level): - """Start a new heading at the specified heading level - - Create a new section whose title is 'heading' and which is placed - in the docutils node tree as a child of the most recent level-1 - heading. Subsequent document sections (commands, freeform doc chun= ks, - etc) will be placed as children of this new heading section. - """ - if len(self._active_headings) < level: - raise QAPISemError(self._cur_doc.info, - 'Level %d subheading found outside a ' - 'level %d heading' - % (level, level - 1)) - snode =3D self._make_section(heading) - self._active_headings[level - 1] +=3D snode - self._active_headings =3D self._active_headings[:level] - self._active_headings.append(snode) - return snode - - def _add_node_to_current_heading(self, node): - """Add the node to whatever the current active heading is""" - self._active_headings[-1] +=3D node - - def freeform(self, doc): - """Add a piece of 'freeform' documentation to the document tree - - A 'freeform' document chunk doesn't relate to any particular - symbol (for instance, it could be an introduction). - - If the freeform document starts with a line of the form - '=3D Heading text', this is a section or subsection heading, with - the heading level indicated by the number of '=3D' signs. - """ - - # QAPIDoc documentation says free-form documentation blocks - # must have only a body section, nothing else. - assert not doc.sections - assert not doc.args - assert not doc.features - self._cur_doc =3D doc - - text =3D doc.body.text - if re.match(r'=3D+ ', text): - # Section/subsection heading (if present, will always be - # the first line of the block) - (heading, _, text) =3D text.partition('\n') - (leader, _, heading) =3D heading.partition(' ') - node =3D self._start_new_heading(heading, len(leader)) - if text =3D=3D '': - return - else: - node =3D nodes.container() - - self._parse_text_into_node(text, node) - self._cur_doc =3D None - - def _parse_text_into_node(self, doctext, node): - """Parse a chunk of QAPI-doc-format text into the node - - The doc comment can contain most inline rST markup, including - bulleted and enumerated lists. - As an extra permitted piece of markup, @var will be turned - into ``var``. - """ - - # Handle the "@var means ``var`` case - doctext =3D re.sub(r'@([\w-]+)', r'``\1``', doctext) - - rstlist =3D ViewList() - for line in doctext.splitlines(): - # The reported line number will always be that of the start li= ne - # of the doc comment, rather than the actual location of the e= rror. - # Being more precise would require overhaul of the QAPIDoc cla= ss - # to track lines more exactly within all the sub-parts of the = doc - # comment, as well as counting lines here. - rstlist.append(line, self._cur_doc.info.fname, - self._cur_doc.info.line) - # Append a blank line -- in some cases rST syntax errors get - # attributed to the line after one with actual text, and if there - # isn't anything in the ViewList corresponding to that then Sphinx - # 1.6's AutodocReporter will then misidentify the source/line loca= tion - # in the error message (usually attributing it to the top-level - # .rst file rather than the offending .json file). The extra blank - # line won't affect the rendered output. - rstlist.append("", self._cur_doc.info.fname, self._cur_doc.info.li= ne) - self._sphinx_directive.do_parse(rstlist, node) - - def get_document_node(self): - """Return the root docutils node which makes up the document""" - return self._top_node diff --git a/python/tests/qapi-isort.sh b/python/tests/qapi-isort.sh index f31f12d3425..9039389f137 100755 --- a/python/tests/qapi-isort.sh +++ b/python/tests/qapi-isort.sh @@ -1,6 +1,6 @@ #!/bin/sh -e python3 -m isort --sp . -c ../scripts/qapi/ # Force isort to recognize "compat" as a local module and not third-party -python3 -m isort --sp . -c -p compat -p qapidoc_legacy \ +python3 -m isort --sp . -c -p compat \ ../docs/sphinx/qapi_domain.py \ ../docs/sphinx/qapidoc.py --=20 2.48.1 From nobody Sat Nov 15 19:07:36 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1747933442; cv=none; d=zohomail.com; s=zohoarc; b=YqQxWFDkBggXrGRWVGcc7251C5VR7RcdfNUU7jkaav9KirKHlc+HXFkvxGO+QuX2b4bV0ZkeCAr0e2TZJSRPgdiMkB7n3JnMtqZlTLVqS+cqheOmEQsZ53I435hrt5GadQJ/+P+WpffsMNgXcEiAO75v1/AJYtY5Xp0YHE8KVcs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1747933442; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=FULH1aFgLOs2anUTjGkG/x2yAtoUIOWkDyDopVX4MnA=; b=CVw0aXPgGR/kCigtUk4jkWtU//qbgjM/X/NzfThcPYU3TxKdV5hHyM6szzU7GACHgWRuTW6noW4a6Lh3dH9PzW9XM9eRv43eY0XryXmqUhKbzpS7Hbwq8zgpwSloVzj4W/rRgnHCMe5lxdzp0dTE1d9VMhxpCst30UC/G9avGMk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1747933442939901.6580598972439; Thu, 22 May 2025 10:04:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uI9KZ-0003oe-6q; Thu, 22 May 2025 13:03:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uI9KI-0003ju-6F for qemu-devel@nongnu.org; Thu, 22 May 2025 13:03:26 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uI9KD-0008AL-TK for qemu-devel@nongnu.org; Thu, 22 May 2025 13:03:25 -0400 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-438-0xqAyOMdMGSSQjSFOUI1xw-1; Thu, 22 May 2025 13:03:16 -0400 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 67721180087F; Thu, 22 May 2025 17:03:08 +0000 (UTC) Received: from jsnow-thinkpadp16vgen1.westford.csb (unknown [10.22.64.178]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 341A819560B0; Thu, 22 May 2025 17:02:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1747933399; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FULH1aFgLOs2anUTjGkG/x2yAtoUIOWkDyDopVX4MnA=; b=bPB06P35W+oA6/mWfJHeaUUGgXI5wdZl0mSnxSOVlOFH7lhw4wuFdhXIH0/E7VSfED4PTZ o7Fh64Dxl/DVKFJhs3jdV7P1HFZ0yvQRbARSk8s6iGAdccvH5msjwYwczwyvUz5OUpRLYL /wNWJi6qOJTp0nZkbb6mDzdN6hg8cmA= X-MC-Unique: 0xqAyOMdMGSSQjSFOUI1xw-1 X-Mimecast-MFC-AGG-ID: 0xqAyOMdMGSSQjSFOUI1xw_1747933388 From: John Snow To: qemu-devel@nongnu.org Cc: Fan Ni , Zhao Liu , Kashyap Chamarthy , "Michael S. Tsirkin" , Vladimir Sementsov-Ogievskiy , qemu-block@nongnu.org, Marcel Apfelbaum , Jonathan Cameron , Ani Sinha , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Zhenwei Pi , Jason Wang , Peter Maydell , Fabiano Rosas , Paolo Bonzini , Alex Williamson , Stefan Hajnoczi , John Snow , Hanna Reitz , Jiri Pirko , Igor Mammedov , "Gonglei (Arei)" , Eric Blake , Gerd Hoffmann , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Michael Roth , Yanan Wang , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Lukas Straub , Stefano Garzarella , Stefan Berger , Mads Ynddal , Konstantin Kostiuk , Peter Xu , Eduardo Habkost , Kevin Wolf , Markus Armbruster , Cleber Rosa , =?UTF-8?q?Alex=20Benn=C3=A9e?= Subject: [PATCH 3/3] docs: remove special parsing for freeform sections Date: Thu, 22 May 2025 13:02:19 -0400 Message-ID: <20250522170219.58058-4-jsnow@redhat.com> In-Reply-To: <20250522170219.58058-1-jsnow@redhat.com> References: <20250522170219.58058-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -23 X-Spam_score: -2.4 X-Spam_bar: -- X-Spam_report: (-2.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.275, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, WEIRD_QUOTING=0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1747933445104116600 Content-Type: text/plain; charset="utf-8" This change removes special parsing for freeform sections and allows them to simply be unmodified rST syntax. The existing headings in the QAPI schema are adjusted to reflect the new paradigm. Markus: presumably you'll want to update the tests and/or change the parser errors. Please advise! Signed-off-by: John Snow --- docs/devel/qapi-code-gen.rst | 28 ++++++++++++++------- docs/interop/firmware.json | 4 ++- docs/interop/vhost-user.json | 4 ++- docs/sphinx/qapidoc.py | 37 +--------------------------- qapi/acpi.json | 4 ++- qapi/audio.json | 4 ++- qapi/authz.json | 4 ++- qapi/block-core.json | 3 ++- qapi/block-export.json | 3 ++- qapi/block.json | 7 ++++-- qapi/char.json | 4 ++- qapi/common.json | 4 ++- qapi/compat.json | 4 ++- qapi/control.json | 4 ++- qapi/crypto.json | 4 ++- qapi/cryptodev.json | 4 ++- qapi/cxl.json | 4 ++- qapi/dump.json | 4 ++- qapi/ebpf.json | 4 ++- qapi/error.json | 4 ++- qapi/introspect.json | 4 ++- qapi/job.json | 4 ++- qapi/machine-common.json | 4 ++- qapi/machine.json | 4 ++- qapi/migration.json | 4 ++- qapi/misc.json | 4 ++- qapi/net.json | 4 ++- qapi/pci.json | 4 ++- qapi/qapi-schema.json | 4 ++- qapi/qdev.json | 4 ++- qapi/qom.json | 4 ++- qapi/replay.json | 4 ++- qapi/rocker.json | 4 ++- qapi/run-state.json | 4 ++- qapi/sockets.json | 4 ++- qapi/stats.json | 4 ++- qapi/tpm.json | 4 ++- qapi/trace.json | 4 ++- qapi/transaction.json | 4 ++- qapi/uefi.json | 4 ++- qapi/ui.json | 14 ++++++++--- qapi/vfio.json | 4 ++- qapi/virtio.json | 4 ++- qapi/yank.json | 4 ++- scripts/qapi/parser.py | 7 ------ storage-daemon/qapi/qapi-schema.json | 8 ++++-- tests/qapi-schema/doc-good.json | 10 +++++--- 47 files changed, 166 insertions(+), 103 deletions(-) diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index 231cc0fecf7..dfdbeac5a5a 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -876,25 +876,35 @@ structuring content. Headings and subheadings ~~~~~~~~~~~~~~~~~~~~~~~~ =20 -A free-form documentation comment containing a line which starts with -some ``=3D`` symbols and then a space defines a section heading:: +Free-form documentation does not start with ``@SYMBOL`` and can contain +arbitrary rST markup. Headings can be marked up using the standard rST +syntax:: =20 ## - # =3D This is a top level heading + # ************************* + # This is a level 2 heading + # ************************* # # This is a free-form comment which will go under the # top level heading. ## =20 ## - # =3D=3D This is a second level heading + # This is a third level heading + # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D + # + # Level 4 + # _______ + # + # Level 5 + # ^^^^^^^ + # + # Level 6 + # """"""" ## =20 -A heading line must be the first line of the documentation -comment block. - -Section headings must always be correctly nested, so you can only -define a third-level heading inside a second-level heading, and so on. +Level 1 headings are reserved for use by the generated documentation +page itself, leaving level 2 as the highest level that should be used. =20 =20 Documentation markup diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json index 745d21d8223..f46fdedfa89 100644 --- a/docs/interop/firmware.json +++ b/docs/interop/firmware.json @@ -11,7 +11,9 @@ # later. See the COPYING file in the top-level directory. =20 ## -# =3D Firmware +# ******** +# Firmware +# ******** ## =20 { 'pragma': { diff --git a/docs/interop/vhost-user.json b/docs/interop/vhost-user.json index b6ade9e4931..095eb99cf79 100644 --- a/docs/interop/vhost-user.json +++ b/docs/interop/vhost-user.json @@ -10,7 +10,9 @@ # later. See the COPYING file in the top-level directory. =20 ## -# =3D vhost user backend discovery & capabilities +# ******************************************* +# vhost user backend discovery & capabilities +# ******************************************* ## =20 ## diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py index c9c477378f5..cdf556c2a3c 100644 --- a/docs/sphinx/qapidoc.py +++ b/docs/sphinx/qapidoc.py @@ -391,44 +391,9 @@ def visit_module(self, path: str) -> None: self.ensure_blank_line() =20 def visit_freeform(self, doc: QAPIDoc) -> None: - # TODO: Once the old qapidoc transformer is deprecated, freeform - # sections can be updated to pure rST, and this transformed remove= d. - # - # For now, translate our micro-format into rST. Code adapted - # from Peter Maydell's freeform(). - assert len(doc.all_sections) =3D=3D 1, doc.all_sections body =3D doc.all_sections[0] - text =3D body.text - info =3D doc.info - - if re.match(r"=3D+ ", text): - # Section/subsection heading (if present, will always be the - # first line of the block) - (heading, _, text) =3D text.partition("\n") - (leader, _, heading) =3D heading.partition(" ") - # Implicit +1 for heading in the containing .rst doc - level =3D len(leader) + 1 - - # https://www.sphinx-doc.org/en/master/usage/restructuredtext/= basics.html#sections - markers =3D ' #*=3D_^"' - overline =3D level <=3D 2 - marker =3D markers[level] - - self.ensure_blank_line() - # This credits all 2 or 3 lines to the single source line. - if overline: - self.add_line(marker * len(heading), info) - self.add_line(heading, info) - self.add_line(marker * len(heading), info) - self.ensure_blank_line() - - # Eat blank line(s) and advance info - trimmed =3D text.lstrip("\n") - text =3D trimmed - info =3D info.next_line(len(text) - len(trimmed) + 1) - - self.add_lines(text, info) + self.add_lines(body.text, doc.info) self.ensure_blank_line() =20 def visit_entity(self, ent: QAPISchemaDefinition) -> None: diff --git a/qapi/acpi.json b/qapi/acpi.json index 045dab6228b..b67e4583161 100644 --- a/qapi/acpi.json +++ b/qapi/acpi.json @@ -6,7 +6,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later =20 ## -# =3D ACPI +# **** +# ACPI +# **** ## =20 ## diff --git a/qapi/audio.json b/qapi/audio.json index dd5a58d13e6..3bc03de4c25 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -7,7 +7,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Audio +# ***** +# Audio +# ***** ## =20 ## diff --git a/qapi/authz.json b/qapi/authz.json index 7fc6e3032ea..ad1b4b3af0c 100644 --- a/qapi/authz.json +++ b/qapi/authz.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D User authorization +# ****************** +# User authorization +# ****************** ## =20 ## diff --git a/qapi/block-core.json b/qapi/block-core.json index b1937780e19..d6f07e36bf6 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2,7 +2,8 @@ # vim: filetype=3Dpython =20 ## -# =3D=3D Block core (VM unrelated) +# Block core (VM unrelated) +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D ## =20 { 'include': 'common.json' } diff --git a/qapi/block-export.json b/qapi/block-export.json index c783e01a532..606fcd061b4 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -2,7 +2,8 @@ # vim: filetype=3Dpython =20 ## -# =3D=3D Block device exports +# Block device exports +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D ## =20 { 'include': 'sockets.json' } diff --git a/qapi/block.json b/qapi/block.json index e66666f5c64..ca370896cbb 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -2,13 +2,16 @@ # vim: filetype=3Dpython =20 ## -# =3D Block devices +# ************* +# Block devices +# ************* ## =20 { 'include': 'block-core.json' } =20 ## -# =3D=3D Additional block stuff (VM related) +# Additional block stuff (VM related) +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D ## =20 ## diff --git a/qapi/char.json b/qapi/char.json index dde2f9538f8..e740e28992f 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Character devices +# ***************** +# Character devices +# ***************** ## =20 { 'include': 'sockets.json' } diff --git a/qapi/common.json b/qapi/common.json index 0e3a0bbbfb0..af7e3d618a7 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D Common data types +# ***************** +# Common data types +# ***************** ## =20 ## diff --git a/qapi/compat.json b/qapi/compat.json index 42034d9368c..90b8d51cf27 100644 --- a/qapi/compat.json +++ b/qapi/compat.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D Compatibility policy +# ******************** +# Compatibility policy +# ******************** ## =20 ## diff --git a/qapi/control.json b/qapi/control.json index 336386f79e1..0ecc2117ec8 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -3,7 +3,9 @@ # =20 ## -# =3D QMP monitor control +# ******************* +# QMP monitor control +# ******************* ## =20 ## diff --git a/qapi/crypto.json b/qapi/crypto.json index c9d967d782e..55a0bb4073f 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Cryptography +# ************ +# Cryptography +# ************ ## =20 ## diff --git a/qapi/cryptodev.json b/qapi/cryptodev.json index 04d0e21d209..e50e21a7dfb 100644 --- a/qapi/cryptodev.json +++ b/qapi/cryptodev.json @@ -5,7 +5,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Cryptography devices +# ******************** +# Cryptography devices +# ******************** ## =20 ## diff --git a/qapi/cxl.json b/qapi/cxl.json index dd947d3bbc8..fee13593a1d 100644 --- a/qapi/cxl.json +++ b/qapi/cxl.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D CXL devices +# *********** +# CXL devices +# *********** ## =20 ## diff --git a/qapi/dump.json b/qapi/dump.json index d7826c0e323..36a12662b64 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -5,7 +5,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Dump guest memory +# ***************** +# Dump guest memory +# ***************** ## =20 ## diff --git a/qapi/ebpf.json b/qapi/ebpf.json index db19ae850fc..d45054e6663 100644 --- a/qapi/ebpf.json +++ b/qapi/ebpf.json @@ -5,7 +5,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D eBPF Objects +# ************ +# eBPF Objects +# ************ # # eBPF object is an ELF binary that contains the eBPF program and eBPF # map description(BTF). Overall, eBPF object should contain the diff --git a/qapi/error.json b/qapi/error.json index 135c1e82319..54cb02fb880 100644 --- a/qapi/error.json +++ b/qapi/error.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D QMP errors +# ********** +# QMP errors +# ********** ## =20 ## diff --git a/qapi/introspect.json b/qapi/introspect.json index 01bb242947c..da1c223d548 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -10,7 +10,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D QMP introspection +# ***************** +# QMP introspection +# ***************** ## =20 ## diff --git a/qapi/job.json b/qapi/job.json index cfc3beedd21..506f6b41ef5 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D Background jobs +# *************** +# Background jobs +# *************** ## =20 ## diff --git a/qapi/machine-common.json b/qapi/machine-common.json index 298e51f373a..0f01599130c 100644 --- a/qapi/machine-common.json +++ b/qapi/machine-common.json @@ -5,7 +5,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Common machine types +# ******************** +# Common machine types +# ******************** ## =20 ## diff --git a/qapi/machine.json b/qapi/machine.json index c8feb9fe17b..630046d6856 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -5,7 +5,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Machines +# ******** +# Machines +# ******** ## =20 { 'include': 'common.json' } diff --git a/qapi/migration.json b/qapi/migration.json index 8b9c53595c4..4d961a7d206 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Migration +# ********* +# Migration +# ********* ## =20 { 'include': 'common.json' } diff --git a/qapi/misc.json b/qapi/misc.json index 559b66f2017..fad74569cad 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Miscellanea +# *********** +# Miscellanea +# *********** ## =20 { 'include': 'common.json' } diff --git a/qapi/net.json b/qapi/net.json index 310cc4fd190..337c3a06966 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Net devices +# *********** +# Net devices +# *********** ## =20 { 'include': 'sockets.json' } diff --git a/qapi/pci.json b/qapi/pci.json index dc85a41d28b..a8671cd9ac3 100644 --- a/qapi/pci.json +++ b/qapi/pci.json @@ -6,7 +6,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later =20 ## -# =3D PCI +# *** +# PCI +# *** ## =20 ## diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 7bc600bb768..21273c8ecdf 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -1,7 +1,9 @@ # -*- Mode: Python -*- # vim: filetype=3Dpython ## -# =3D Introduction +# ************ +# Introduction +# ************ # # This manual describes the commands and events supported by the QEMU # Monitor Protocol (QMP). diff --git a/qapi/qdev.json b/qapi/qdev.json index 32c7d100463..441ed518b87 100644 --- a/qapi/qdev.json +++ b/qapi/qdev.json @@ -5,7 +5,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Device infrastructure (qdev) +# **************************** +# Device infrastructure (qdev) +# **************************** ## =20 { 'include': 'qom.json' } diff --git a/qapi/qom.json b/qapi/qom.json index 04c118e4d61..af2a69b0222 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -10,7 +10,9 @@ { 'include': 'crypto.json' } =20 ## -# =3D QEMU Object Model (QOM) +# *********************** +# QEMU Object Model (QOM) +# *********************** ## =20 ## diff --git a/qapi/replay.json b/qapi/replay.json index 35e0c4a6926..e46c5c1d3f3 100644 --- a/qapi/replay.json +++ b/qapi/replay.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Record/replay +# ************* +# Record/replay +# ************* ## =20 { 'include': 'common.json' } diff --git a/qapi/rocker.json b/qapi/rocker.json index 0c7ef1f77c8..e4949649526 100644 --- a/qapi/rocker.json +++ b/qapi/rocker.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D Rocker switch device +# ******************** +# Rocker switch device +# ******************** ## =20 ## diff --git a/qapi/run-state.json b/qapi/run-state.json index ce95cfa46b7..0c8c9845f82 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -3,7 +3,9 @@ # =20 ## -# =3D VM run state +# ************ +# VM run state +# ************ ## =20 ## diff --git a/qapi/sockets.json b/qapi/sockets.json index 6a950233158..3b78232a639 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -2,7 +2,9 @@ # vim: filetype=3Dpython =20 ## -# =3D Socket data types +# ***************** +# Socket data types +# ***************** ## =20 ## diff --git a/qapi/stats.json b/qapi/stats.json index 8902ef94e08..78b88881eab 100644 --- a/qapi/stats.json +++ b/qapi/stats.json @@ -9,7 +9,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later =20 ## -# =3D Statistics +# ********** +# Statistics +# ********** ## =20 ## diff --git a/qapi/tpm.json b/qapi/tpm.json index a16a72edb98..e66b107f1d0 100644 --- a/qapi/tpm.json +++ b/qapi/tpm.json @@ -3,7 +3,9 @@ # =20 ## -# =3D TPM (trusted platform module) devices +# ************************************* +# TPM (trusted platform module) devices +# ************************************* ## =20 ## diff --git a/qapi/trace.json b/qapi/trace.json index eb5f63f5135..d08c9c6a889 100644 --- a/qapi/trace.json +++ b/qapi/trace.json @@ -7,7 +7,9 @@ # See the COPYING file in the top-level directory. =20 ## -# =3D Tracing +# ******* +# Tracing +# ******* ## =20 ## diff --git a/qapi/transaction.json b/qapi/transaction.json index 021e383496c..3612f6c320f 100644 --- a/qapi/transaction.json +++ b/qapi/transaction.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Transactions +# ************ +# Transactions +# ************ ## =20 { 'include': 'block-core.json' } diff --git a/qapi/uefi.json b/qapi/uefi.json index bdfcabe1df4..254f30313d4 100644 --- a/qapi/uefi.json +++ b/qapi/uefi.json @@ -3,7 +3,9 @@ # =20 ## -# =3D UEFI Variable Store +# ******************* +# UEFI Variable Store +# ******************* # # The qemu efi variable store implementation (hw/uefi/) uses this to # store non-volatile variables in json format on disk. diff --git a/qapi/ui.json b/qapi/ui.json index c536d4e5241..dade7b8345f 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Remote desktop +# ************** +# Remote desktop +# ************** ## =20 { 'include': 'common.json' } @@ -200,7 +202,8 @@ 'if': 'CONFIG_PIXMAN' } =20 ## -# =3D=3D Spice +# Spice +# =3D=3D=3D=3D=3D ## =20 ## @@ -461,7 +464,8 @@ 'if': 'CONFIG_SPICE' } =20 ## -# =3D=3D VNC +# VNC +# =3D=3D=3D ## =20 ## @@ -794,7 +798,9 @@ 'if': 'CONFIG_VNC' } =20 ## -# =3D Input +# ***** +# Input +# ***** ## =20 ## diff --git a/qapi/vfio.json b/qapi/vfio.json index b53b7caecd7..a1a9c5b673d 100644 --- a/qapi/vfio.json +++ b/qapi/vfio.json @@ -3,7 +3,9 @@ # =20 ## -# =3D VFIO devices +# ************ +# VFIO devices +# ************ ## =20 ## diff --git a/qapi/virtio.json b/qapi/virtio.json index d351d2166ef..9b435481555 100644 --- a/qapi/virtio.json +++ b/qapi/virtio.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Virtio devices +# ************** +# Virtio devices +# ************** ## =20 ## diff --git a/qapi/yank.json b/qapi/yank.json index 30f46c97c98..d13a8e91171 100644 --- a/qapi/yank.json +++ b/qapi/yank.json @@ -3,7 +3,9 @@ # =20 ## -# =3D Yank feature +# ************ +# Yank feature +# ************ ## =20 ## diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 949d9e8bff7..aad7e249f86 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -597,22 +597,15 @@ def get_doc(self) -> 'QAPIDoc': # Free-form documentation doc =3D QAPIDoc(info) doc.ensure_untagged_section(self.info) - first =3D True while line is not None: if match :=3D self._match_at_name_colon(line): raise QAPIParseError( self, "'@%s:' not allowed in free-form documentation" % match.group(1)) - if line.startswith('=3D'): - if not first: - raise QAPIParseError( - self, - "'=3D' heading must come first in a comment bl= ock") doc.append_line(line) self.accept(False) line =3D self.get_doc_line() - first =3D False =20 self.accept() doc.end() diff --git a/storage-daemon/qapi/qapi-schema.json b/storage-daemon/qapi/qap= i-schema.json index 0427594c984..478e7a92b21 100644 --- a/storage-daemon/qapi/qapi-schema.json +++ b/storage-daemon/qapi/qapi-schema.json @@ -14,7 +14,9 @@ # storage daemon. =20 ## -# =3D Introduction +# ************ +# Introduction +# ************ # # This manual describes the commands and events supported by the QEMU # storage daemon QMP. @@ -51,7 +53,9 @@ { 'include': '../../qapi/job.json' } =20 ## -# =3D Block devices +# ************* +# Block devices +# ************* ## { 'include': '../../qapi/block-core.json' } { 'include': '../../qapi/block-export.json' } diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.j= son index 6dcde8fd7e8..183da7df724 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -8,7 +8,9 @@ 'documentation-exceptions': [ 'Enum', 'Variant1', 'Alternate', 'cmd' ]= } } =20 ## -# =3D Section +# ******* +# Section +# ******* ## =20 ## @@ -16,7 +18,8 @@ ## =20 ## -# =3D=3D Subsection +# Subsection +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # # *with emphasis* # @var {in braces} @@ -144,7 +147,8 @@ 'if': { 'not': { 'any': [ 'IFONE', 'IFTWO' ] } } } =20 ## -# =3D=3D Another subsection +# Another subsection +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D ## =20 ## --=20 2.48.1