get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2227550/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2227550,
    "url": "http://patchwork.ozlabs.org/api/patches/2227550/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260423220022.2180059-6-jsnow@redhat.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260423220022.2180059-6-jsnow@redhat.com>",
    "list_archive_url": null,
    "date": "2026-04-23T22:00:14",
    "name": "[05/12] qapi/docs: adjust stub member insertion algorithm",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "5520f31be41aa45fa301ac9148c67b0857a0ad05",
    "submitter": {
        "id": 64343,
        "url": "http://patchwork.ozlabs.org/api/people/64343/?format=api",
        "name": "John Snow",
        "email": "jsnow@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260423220022.2180059-6-jsnow@redhat.com/mbox/",
    "series": [
        {
            "id": 501255,
            "url": "http://patchwork.ozlabs.org/api/series/501255/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=501255",
            "date": "2026-04-23T22:00:11",
            "name": "qapi: add formal \"intro\" section",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/501255/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2227550/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2227550/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=ZZNjRKCv;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g1qnv2zN8z1yDD\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 08:02:27 +1000 (AEST)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wG26V-0005iq-Vp; Thu, 23 Apr 2026 18:01:00 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <jsnow@redhat.com>) id 1wG26S-0005iX-Vt\n for qemu-devel@nongnu.org; Thu, 23 Apr 2026 18:00:57 -0400",
            "from us-smtp-delivery-124.mimecast.com ([170.10.133.124])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <jsnow@redhat.com>) id 1wG26Q-0005o7-VP\n for qemu-devel@nongnu.org; Thu, 23 Apr 2026 18:00:56 -0400",
            "from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-246-09FxVxLhOfCM_DNO96xqfw-1; Thu,\n 23 Apr 2026 18:00:46 -0400",
            "from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id A32A918004A9; Thu, 23 Apr 2026 22:00:44 +0000 (UTC)",
            "from jsnow-thinkpadp16vgen1.westford.csb (unknown [10.22.64.143])\n by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 06AE13007572; Thu, 23 Apr 2026 22:00:40 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1776981654;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=H8St3ZLHNQCULxq0KdxqVYwinUoafALzLhiR1oK0wvQ=;\n b=ZZNjRKCvwSw6QiDEllVL9RxbsmY1/WHkdKJKM+6jE06YkV4X1n3F5JB3AZ8ZcbTyrM40XV\n 6h6+ZdwgMsm3/u1O9woF/M1L6M8TCA1dw9HMECUQtUyx9QXDUYJcDlYXedryQxwvwSS5Vb\n 9leRwUpLREkHmwcWM11mFdKhvOaCAeE=",
        "X-MC-Unique": "09FxVxLhOfCM_DNO96xqfw-1",
        "X-Mimecast-MFC-AGG-ID": "09FxVxLhOfCM_DNO96xqfw_1776981644",
        "From": "John Snow <jsnow@redhat.com>",
        "To": "qemu-devel@nongnu.org",
        "Cc": "Igor Mammedov <imammedo@redhat.com>,\n Mauro Carvalho Chehab <mchehab+huawei@kernel.org>,\n \"Michael S. Tsirkin\" <mst@redhat.com>, Michael Roth <michael.roth@amd.com>,\n Markus Armbruster <armbru@redhat.com>, Ani Sinha <anisinha@redhat.com>,\n Gerd Hoffmann <kraxel@redhat.com>, Eric Blake <eblake@redhat.com>,\n Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>, =?utf-8?q?Philippe_Ma?=\n\t=?utf-8?q?thieu-Daud=C3=A9?= <philmd@linaro.org>, =?utf-8?q?Marc-Andr=C3=A9?=\n\t=?utf-8?q?_Lureau?= <marcandre.lureau@redhat.com>,\n Richard Henderson <richard.henderson@linaro.org>,\n Paolo Bonzini <pbonzini@redhat.com>,\n Peter Maydell <peter.maydell@linaro.org>, John Snow <jsnow@redhat.com>",
        "Subject": "[PATCH 05/12] qapi/docs: adjust stub member insertion algorithm",
        "Date": "Thu, 23 Apr 2026 18:00:14 -0400",
        "Message-ID": "<20260423220022.2180059-6-jsnow@redhat.com>",
        "In-Reply-To": "<20260423220022.2180059-1-jsnow@redhat.com>",
        "References": "<20260423220022.2180059-1-jsnow@redhat.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.4",
        "Received-SPF": "pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com;\n helo=us-smtp-delivery-124.mimecast.com",
        "X-Spam_score_int": "-20",
        "X-Spam_score": "-2.1",
        "X-Spam_bar": "--",
        "X-Spam_report": "(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001,\n SPF_HELO_PASS=-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": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "A forthcoming patch removes the implicit PLAIN section that always\nstarts a QAPIDoc section list. Further future changes begin converting\n\"PLAIN\" sections to \"INTRO\" sections. To accommodate this, the insertion\nalgorithm that places stub and dummy members must be adjusted to cope.\n\nThis algorithm can handle zero-or-more PLAIN *or* INTRO sections at the\nbeginning of a QAPIDoc object.\n\nSince we have three places that need to insert stub members, take the\nopportunity to unify and deduplicate this code.\n\nSigned-off-by: John Snow <jsnow@redhat.com>\n---\n docs/sphinx/qapidoc.py | 36 ++++++++---------\n scripts/qapi/parser.py | 90 +++++++++++++++++++++++++++---------------\n 2 files changed, 75 insertions(+), 51 deletions(-)",
    "diff": "diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py\nindex 1f7c15b7075..70ab9cdc214 100644\n--- a/docs/sphinx/qapidoc.py\n+++ b/docs/sphinx/qapidoc.py\n@@ -349,30 +349,32 @@ def _get_target(\n                 )\n \n     def visit_sections(self, ent: QAPISchemaDefinition) -> None:\n+        # Generate a placeholder right after the member section(s) which\n+        # will be used to generate documentation for \"The members of...\"\n+        # pointers in the rendered document.\n+        # This is a temporary hack until the inliner is merged.\n+        if ent.doc:\n+            ent.doc.append_member_stub(\n+                QAPIDoc.ArgSection(\n+                    ent.doc.info, QAPIDoc.Kind.MEMBER, \"q_dummy\"\n+                )\n+            )\n+\n         sections = ent.doc.all_sections if ent.doc else []\n \n-        # Determine the index location at which we should generate\n-        # documentation for \"The members of ...\" pointers. This should\n-        # go at the end of the members section(s) if any. Note that\n-        # index 0 is assumed to be a plain intro section, even if it is\n-        # empty; and that a members section if present will always\n-        # immediately follow the opening PLAIN section.\n-        gen_index = 1\n-        if len(sections) > 1:\n-            while sections[gen_index].kind == QAPIDoc.Kind.MEMBER:\n-                gen_index += 1\n-                if gen_index >= len(sections):\n-                    break\n-\n         # Add sections in source order:\n-        for i, section in enumerate(sections):\n+        for section in sections:\n             section.text = self.reformat_arobase(section.text)\n \n             if section.kind.name in (\"PLAIN\", \"INTRO\"):\n                 self.visit_paragraph(section)\n             elif section.kind == QAPIDoc.Kind.MEMBER:\n                 assert isinstance(section, QAPIDoc.ArgSection)\n-                self.visit_member(section)\n+                if section.name == \"q_dummy\":\n+                    # Generate \"The members of ...\" entries if necessary\n+                    self._insert_member_pointer(ent)\n+                else:\n+                    self.visit_member(section)\n             elif section.kind == QAPIDoc.Kind.FEATURE:\n                 assert isinstance(section, QAPIDoc.ArgSection)\n                 self.visit_feature(section)\n@@ -386,10 +388,6 @@ def visit_sections(self, ent: QAPISchemaDefinition) -> None:\n             else:\n                 assert False\n \n-            # Generate \"The members of ...\" entries if necessary:\n-            if i == gen_index - 1:\n-                self._insert_member_pointer(ent)\n-\n         self.ensure_blank_line()\n \n     # Transmogrification core methods\ndiff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py\nindex 97e7dacb0fd..b21796b3e80 100644\n--- a/scripts/qapi/parser.py\n+++ b/scripts/qapi/parser.py\n@@ -816,6 +816,58 @@ def new_feature(self, info: QAPISourceInfo, name: str) -> None:\n     def append_line(self, line: str) -> None:\n         self.all_sections[-1].append_line(line)\n \n+    def _insert_near_kind(\n+        self,\n+        kind: 'QAPIDoc.Kind',\n+        new_sect: 'QAPIDoc.Section',\n+        after: bool = False,\n+    ) -> bool:\n+        \"\"\"Insert or append a new doc section at a specific point.\"\"\"\n+        for idx, sect in enumerate(reversed(self.all_sections)):\n+            if sect.kind == kind:\n+                pos = len(self.all_sections) - idx - 1\n+                if after:\n+                    pos += 1\n+                self.all_sections.insert(pos, new_sect)\n+                return True\n+        return False\n+\n+    def _insert_after_intro(\n+        self,\n+        section: 'QAPIDoc.Section',\n+    ) -> None:\n+        \"\"\"\n+        Insert a section immediately after the intro section.\n+\n+        While we convert PLAIN sections to INTRO sections, all\n+        contiguous INTRO/PLAIN sections at the start of a QAPIDoc\n+        section list are treated as \"the intro\".\n+\n+        Once INTRO conversion is complete, this helper will no longer be\n+        needed and ``_insert_near_kind(QAPIDoc.Kind.INTRO, ...)`` will\n+        be sufficient.\n+        \"\"\"\n+        index = 0\n+        for index, ref_section in enumerate(self.all_sections):\n+            if ref_section.kind.name in (\"PLAIN\", \"INTRO\"):\n+                continue\n+            break\n+        else:\n+            index += 1\n+\n+        self.all_sections.insert(index, section)\n+\n+    def append_member_stub(self, stub: 'QAPIDoc.Section') -> None:\n+\n+        \"\"\"\n+        Append a stub section after any Member sections.\n+        \"\"\"\n+        if self._insert_near_kind(QAPIDoc.Kind.MEMBER, stub, True):\n+            return\n+\n+        # No MEMBER sections present. Insert after INTRO/PLAIN sections.\n+        self._insert_after_intro(stub)\n+\n     def connect_member(self, member: 'QAPISchemaMember') -> None:\n         if member.name not in self._args:\n             assert member.info\n@@ -825,20 +877,10 @@ def connect_member(self, member: 'QAPISchemaMember') -> None:\n                                    % (member.role, member.name))\n             # Insert stub documentation section for missing member docs.\n             # TODO: drop when undocumented members are outlawed\n-\n-            section = QAPIDoc.ArgSection(\n+            stub_section = QAPIDoc.ArgSection(\n                 self.info, QAPIDoc.Kind.MEMBER, member.name)\n-            self._args[member.name] = section\n-\n-            # Determine where to insert stub doc - it should go at the\n-            # end of the members section(s), if any. Note that index 0\n-            # is assumed to be an untagged intro section, even if it is\n-            # empty.\n-            index = 1\n-            if len(self.all_sections) > 1:\n-                while self.all_sections[index].kind == QAPIDoc.Kind.MEMBER:\n-                    index += 1\n-            self.all_sections.insert(index, section)\n+            self._args[member.name] = stub_section\n+            self.append_member_stub(stub_section)\n \n         self._args[member.name].connect(member)\n \n@@ -851,27 +893,13 @@ def connect_feature(self, feature: 'QAPISchemaFeature') -> None:\n \n     def ensure_returns(self, info: QAPISourceInfo) -> None:\n \n-        def _insert_near_kind(\n-            kind: QAPIDoc.Kind,\n-            new_sect: QAPIDoc.Section,\n-            after: bool = False,\n-        ) -> bool:\n-            for idx, sect in enumerate(reversed(self.all_sections)):\n-                if sect.kind == kind:\n-                    pos = len(self.all_sections) - idx - 1\n-                    if after:\n-                        pos += 1\n-                    self.all_sections.insert(pos, new_sect)\n-                    return True\n-            return False\n-\n         if any(s.kind == QAPIDoc.Kind.RETURNS for s in self.all_sections):\n             return\n \n         # Stub \"Returns\" section for undocumented returns value\n         stub = QAPIDoc.Section(info, QAPIDoc.Kind.RETURNS)\n \n-        if any(_insert_near_kind(kind, stub, after) for kind, after in (\n+        if any(self._insert_near_kind(kind, stub, after) for kind, after in (\n                 # 1. If arguments, right after those.\n                 (QAPIDoc.Kind.MEMBER, True),\n                 # 2. Elif errors, right *before* those.\n@@ -881,10 +909,8 @@ def _insert_near_kind(\n         )):\n             return\n \n-        # Otherwise, it should go right after the intro. The intro\n-        # is always the first section and is always present (even\n-        # when empty), so we can insert directly at index=1 blindly.\n-        self.all_sections.insert(1, stub)\n+        # Otherwise, it should go right after the intro.\n+        self._insert_after_intro(stub)\n \n     def check_expr(self, expr: QAPIExpression) -> None:\n         if 'command' in expr:\n",
    "prefixes": [
        "05/12"
    ]
}