get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2230966,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2230966/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260430090534.841894-14-pbonzini@redhat.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/1.1/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": ""
    },
    "msgid": "<20260430090534.841894-14-pbonzini@redhat.com>",
    "date": "2026-04-30T09:05:34",
    "name": "[13/13] minikconf: add mypy annotations",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "5fdd82147ee995cb9a98a02720f9bd1c67c52f88",
    "submitter": {
        "id": 2701,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/2701/?format=api",
        "name": "Paolo Bonzini",
        "email": "pbonzini@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260430090534.841894-14-pbonzini@redhat.com/mbox/",
    "series": [
        {
            "id": 502245,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/502245/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=502245",
            "date": "2026-04-30T09:05:25",
            "name": "kconfig cleanups and mypy annotations",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/502245/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2230966/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2230966/checks/",
    "tags": {},
    "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=ivY3ZPGm;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=google header.b=i8YQhOYp;\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 4g5pGG0C7Tz1yGq\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 19:07:18 +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 1wINLe-0008Ku-J0; Thu, 30 Apr 2026 05:06:18 -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 <pbonzini@redhat.com>)\n id 1wINLT-00082M-Mg\n for qemu-devel@nongnu.org; Thu, 30 Apr 2026 05:06:10 -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 <pbonzini@redhat.com>)\n id 1wINLQ-0003AB-V6\n for qemu-devel@nongnu.org; Thu, 30 Apr 2026 05:06:07 -0400",
            "from mail-wr1-f72.google.com (mail-wr1-f72.google.com\n [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-460-lk1blbmePDOfUZa2tdNuHw-1; Thu, 30 Apr 2026 05:06:02 -0400",
            "by mail-wr1-f72.google.com with SMTP id\n ffacd0b85a97d-43d121c4271so464108f8f.3\n for <qemu-devel@nongnu.org>; Thu, 30 Apr 2026 02:06:01 -0700 (PDT)",
            "from [192.168.10.48] ([151.49.85.67])\n by smtp.gmail.com with ESMTPSA id\n ffacd0b85a97d-447b7217c56sm11675508f8f.20.2026.04.30.02.05.57\n for <qemu-devel@nongnu.org>\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 30 Apr 2026 02:05:58 -0700 (PDT)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777539964;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:mime-version:mime-version:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=LVORDiAtsyF67SvxbxKKHAquX3JZKNCa8iS/ZxVnKeU=;\n b=ivY3ZPGmpIqK+V8H46xTcMz2jOrUDf7gd8QM+MFpdNhJrz2XSdAnyAxTD4qMgOfqKXXHC0\n SOVAJZx++sqPrfRgRidDosw+FsYKGU8vCt7jiO1YH40FE4oW/3byEV4o0a3B1X/qQbnDZ4\n M9z0gxOtGAXV1tRq5wrEHi4Baq3TK04=",
            "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=redhat.com; s=google; t=1777539960; x=1778144760; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n :reply-to; bh=LVORDiAtsyF67SvxbxKKHAquX3JZKNCa8iS/ZxVnKeU=;\n b=i8YQhOYpMXMKA1lpkkv8W8uQTs1wJtoUmvLQGJGPKK35p4YfDEvxQ4sgdlBEn0ys3C\n X2vnk71lPuavk3LuKmhbCjF3oek/C5e5z45AMxz7Dufm33Jqm8afzA2SW1SVQutCAzVR\n arWJG3jsBADtpJ3AcVyt/+rEqOId20onsq2neVG3RNJcui1mCxtjb3Zv0t+7CCBzvkxq\n d7+CkSsu/wbQ+Nf+xxmuDz0jewqmgViwvvrCmXnJjFq0X3uIID96EPV17QONsovdtnNc\n uvGruK31vjfm2TonV+G1qCR0GB/v2nNYKdExzXxkKEAtrAxeNydHGEdzBa1NHFI9k3Xe\n B6JA=="
        ],
        "X-MC-Unique": "lk1blbmePDOfUZa2tdNuHw-1",
        "X-Mimecast-MFC-AGG-ID": "lk1blbmePDOfUZa2tdNuHw_1777539961",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777539960; x=1778144760;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to\n :cc:subject:date:message-id:reply-to;\n bh=LVORDiAtsyF67SvxbxKKHAquX3JZKNCa8iS/ZxVnKeU=;\n b=hDOtdlrl2Nw6SO3ou/H/hWuj9AHURMTesmvncV1hGt9O41wO2fO+oidyEOpPCRCuE8\n Zj9vopdZWRF/HVBs44PSoPfStISV+BMqfcSGljewEY7tKJD1yNFrd9wkM40F9wVDGJPA\n 8CkuTW/EWUYn7vV489RGrnOru7p7U0nzX/s2mZddjbhNZ5jFU+XyvuzFuchTw0B56Xvp\n lFROSV6lneAfzx2fr/fQ5S9UvnPnOQ7AXLf/SlVCZoEUiLmlYEzG1ICOz4vJXGITekwE\n BowWNSNua38vtMbb5l5koRyEn/THK60MXl0ziadziXgyu1KvzsZql32MgPEcB1mazTFv\n IuAA==",
        "X-Gm-Message-State": "AOJu0Yx3TNzC0JdI8qKqrY2/af+YuEPGFh8F3bABpYAlyhl1jH7H8Giw\n Rl25wZ5d223guiA9/p6+lB+JJ9Mu3QKlI2QKUJI1HiQObp90yzulxZ8BywRJYa+Ran1EW6f0QG4\n kbzQM/++JLeepQUPMV+mk3cGFRZVdOTzbme8Mf2hv8REJ3h+3ZxMIP8wYyaoPw2ztEvbmhpiaEW\n gHBi1Qu2q7gUdw+2s1yTw06ZSRynLhvMfES3yESl4H",
        "X-Gm-Gg": "AeBDieuJ7zHHoV3rEp89Y6REW1hnz5/dVSmULzp8uGWej+1oiq5+2UDdcO3aa3rvIhK\n YH8VPTlh2IjZuZ/mzRVx7AfVq3JnwJiCOTCPHf5XfK+mvOqONtz0+hXQgahIFXIfX88C6NG1Mkh\n ZE3LAHQ+WpfaQEkbhWG3MEi9ZqxiBXqwtXrjGWwgatPsiALmtciz8vhnjQBihK9TAF4ljJKOO08\n EP0AcGltr8TADNYbqtFxHNtkrTy2oWkcFTwIxCtmVqk2shIk27G+FjJwNMi2Slqzg9Lzy4+yyIT\n KsR7rfh8IyBm0VtPNJ4xdIThwo9GUu2lSgmLyppY5sbcz39G2O7dkbjfzDeH4kw/Ug9WcVp1+PH\n fvvth0gBGymxHKJ7wluj7H3NkAwAegnX8TyBaLJb78K7xek4N8T7JqMEU+nBxh3udHOfjM5SETH\n IF8oiWebTjuridMiGIv5Urhy87RrJWztNVfMM=",
        "X-Received": [
            "by 2002:a5d:588b:0:b0:43f:e7c9:2402 with SMTP id\n ffacd0b85a97d-4493dbdbc78mr3258713f8f.3.1777539959858;\n Thu, 30 Apr 2026 02:05:59 -0700 (PDT)",
            "by 2002:a5d:588b:0:b0:43f:e7c9:2402 with SMTP id\n ffacd0b85a97d-4493dbdbc78mr3258584f8f.3.1777539958650;\n Thu, 30 Apr 2026 02:05:58 -0700 (PDT)"
        ],
        "From": "Paolo Bonzini <pbonzini@redhat.com>",
        "To": "qemu-devel@nongnu.org",
        "Subject": "[PATCH 13/13] minikconf: add mypy annotations",
        "Date": "Thu, 30 Apr 2026 11:05:34 +0200",
        "Message-ID": "<20260430090534.841894-14-pbonzini@redhat.com>",
        "X-Mailer": "git-send-email 2.54.0",
        "In-Reply-To": "<20260430090534.841894-1-pbonzini@redhat.com>",
        "References": "<20260430090534.841894-1-pbonzini@redhat.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Received-SPF": "pass client-ip=170.10.133.124;\n envelope-from=pbonzini@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": "Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>\n---\n python/tests/linters.py |   3 +\n scripts/minikconf.py    | 222 ++++++++++++++++++++++------------------\n 2 files changed, 124 insertions(+), 101 deletions(-)",
    "diff": "diff --git a/python/tests/linters.py b/python/tests/linters.py\nindex 4ce4e8a9805..82b88aebb20 100644\n--- a/python/tests/linters.py\n+++ b/python/tests/linters.py\n@@ -65,6 +65,9 @@ def test_isort_qapi_sphinx(self):\n             ]\n         )\n \n+    def test_mypy_minikconf(self):\n+        check_call([sys.executable, \"-m\", \"mypy\", \"../scripts/minikconf.py\"])\n+\n     def test_mypy_pkg(self):\n         check_call([sys.executable, \"-m\", \"mypy\", \"-p\", \"qemu\"])\n \ndiff --git a/scripts/minikconf.py b/scripts/minikconf.py\nindex 7a2fe865484..6d7dbbf2ccd 100644\n--- a/scripts/minikconf.py\n+++ b/scripts/minikconf.py\n@@ -11,35 +11,40 @@\n # or, at your option, any later version.  See the COPYING file in\n # the top-level directory.\n \n+from __future__ import annotations\n+\n import os\n import random\n import re\n import sys\n+import typing as T\n from dataclasses import dataclass\n \n __all__ = [ 'KconfigDataError', 'KconfigParserError',\n             'KconfigData', 'KconfigParser' ,\n             'defconfig', 'allyesconfig', 'allnoconfig', 'randconfig' ]\n \n+Mangler = T.Callable[[bool], bool]\n+\n @dataclass\n class IncludeInfo:\n     file: str\n     line: int\n     parent: IncludeInfo | None\n \n-    def __iter__(self):\n-        inf = self\n+    def __iter__(self) -> T.Iterator[str]:\n+        inf: IncludeInfo | None = self\n         while inf is not None:\n             yield \"%s:%d\" % (inf.file, inf.line)\n             inf = inf.parent\n \n-    def error_path(self):\n+    def error_path(self) -> str:\n         res = \"\"\n         for loc in self:\n             res = \"In file included from %s:\\n\" % loc + res\n         return res\n \n-def debug_print(*args):\n+def debug_print(*args: object) -> None:\n     #print('# ' + (' '.join(str(x) for x in args)))\n     pass\n \n@@ -54,81 +59,81 @@ def debug_print(*args):\n # -------------------------------------------\n \n class KconfigDataError(Exception):\n-    def __init__(self, msg):\n+    def __init__(self, msg: str) -> None:\n         self.msg = msg\n \n-    def __str__(self):\n+    def __str__(self) -> str:\n         return self.msg\n \n-allyesconfig = lambda x: True\n-allnoconfig = lambda x: False\n-defconfig = lambda x: x\n-randconfig = lambda x: random.randint(0, 1) == 1\n+allyesconfig: Mangler = lambda x: True\n+allnoconfig: Mangler = lambda x: False\n+defconfig: Mangler = lambda x: x\n+randconfig: Mangler = lambda x: random.randint(0, 1) == 1\n \n class KconfigData:\n     class Expr:\n-        def __and__(self, rhs):\n+        def __and__(self, rhs: KconfigData.Expr) -> KconfigData.Expr:\n             return KconfigData.AND(self, rhs)\n-        def __or__(self, rhs):\n+        def __or__(self, rhs: KconfigData.Expr) -> KconfigData.Expr:\n             return KconfigData.OR(self, rhs)\n-        def __invert__(self):\n+        def __invert__(self) -> KconfigData.Expr:\n             return KconfigData.NOT(self)\n \n         # Abstract methods\n-        def add_edges_to(self, var):\n+        def add_edges_to(self, var: KconfigData.Var) -> None:\n             pass\n-        def evaluate(self):\n+        def evaluate(self) -> bool:\n             assert False\n \n     class AND(Expr):\n-        def __init__(self, lhs, rhs):\n+        def __init__(self, lhs: KconfigData.Expr, rhs: KconfigData.Expr) -> None:\n             self.lhs = lhs\n             self.rhs = rhs\n-        def __str__(self):\n+        def __str__(self) -> str:\n             return \"(%s && %s)\" % (self.lhs, self.rhs)\n \n-        def add_edges_to(self, var):\n+        def add_edges_to(self, var: KconfigData.Var) -> None:\n             self.lhs.add_edges_to(var)\n             self.rhs.add_edges_to(var)\n-        def evaluate(self):\n+        def evaluate(self) -> bool:\n             return self.lhs.evaluate() and self.rhs.evaluate()\n \n     class OR(Expr):\n-        def __init__(self, lhs, rhs):\n+        def __init__(self, lhs: KconfigData.Expr, rhs: KconfigData.Expr) -> None:\n             self.lhs = lhs\n             self.rhs = rhs\n-        def __str__(self):\n+        def __str__(self) -> str:\n             return \"(%s || %s)\" % (self.lhs, self.rhs)\n \n-        def add_edges_to(self, var):\n+        def add_edges_to(self, var: KconfigData.Var) -> None:\n             self.lhs.add_edges_to(var)\n             self.rhs.add_edges_to(var)\n-        def evaluate(self):\n+        def evaluate(self) -> bool:\n             return self.lhs.evaluate() or self.rhs.evaluate()\n \n     class NOT(Expr):\n-        def __init__(self, lhs):\n+        def __init__(self, lhs: KconfigData.Expr) -> None:\n             self.lhs = lhs\n-        def __str__(self):\n+        def __str__(self) -> str:\n             return \"!%s\" % (self.lhs)\n \n-        def add_edges_to(self, var):\n+        def add_edges_to(self, var: KconfigData.Var) -> None:\n             self.lhs.add_edges_to(var)\n-        def evaluate(self):\n+        def evaluate(self) -> bool:\n             return not self.lhs.evaluate()\n \n     class Var(Expr):\n-        def __init__(self, name):\n+        def __init__(self, name: str) -> None:\n             self.name = name\n-            self.value = None\n-            self.outgoing = set()\n-            self.clauses_for_var = list()\n-        def __str__(self):\n+            self.value: bool | None = None\n+            self.outgoing: set[KconfigData.Var] = set()\n+            self.clauses_for_var: list[KconfigData.Clause] = []\n+        def __str__(self) -> str:\n             return self.name\n \n-        def has_value(self):\n+        def has_value(self) -> bool:\n             return self.value is not None\n-        def set_value(self, val, clause):\n+        def set_value(self, val: bool, clause: KconfigData.Clause) -> None:\n             self.clauses_for_var.append(clause)\n             if self.has_value() and self.value != val:\n                 print(\"The following clauses were found for \" + self.name, file=sys.stderr)\n@@ -139,7 +144,8 @@ def set_value(self, val, clause):\n             self.value = val\n \n         # depth first search of the dependency graph\n-        def dfs(self, visited, f):\n+        def dfs(self, visited: set[KconfigData.Var],\n+                f: T.Callable[[KconfigData.Var], None]) -> None:\n             if self in visited:\n                 return\n             visited.add(self)\n@@ -147,87 +153,89 @@ def dfs(self, visited, f):\n                 v.dfs(visited, f)\n             f(self)\n \n-        def add_edges_to(self, var):\n+        def add_edges_to(self, var: KconfigData.Var) -> None:\n             self.outgoing.add(var)\n-        def evaluate(self):\n+        def evaluate(self) -> bool:\n             if not self.has_value():\n                 raise KconfigDataError('cycle found including %s' % self)\n+            assert self.value is not None\n             return self.value\n \n     class Clause:\n-        def __init__(self, dest):\n+        def __init__(self, dest: KconfigData.Var) -> None:\n             self.dest = dest\n-        def priority(self):\n+        def priority(self) -> int:\n             return 0\n-        def process(self):\n+        def process(self) -> None:\n             pass\n \n     class AssignmentClause(Clause):\n-        def __init__(self, dest, value):\n+        def __init__(self, dest: KconfigData.Var, value: bool) -> None:\n             KconfigData.Clause.__init__(self, dest)\n             self.value = value\n-        def __str__(self):\n+        def __str__(self) -> str:\n             return \"CONFIG_%s=%s\" % (self.dest, 'y' if self.value else 'n')\n \n-        def process(self):\n+        def process(self) -> None:\n             self.dest.set_value(self.value, self)\n \n     class DefaultClause(Clause):\n-        def __init__(self, dest, value, cond=None):\n+        def __init__(self, dest: KconfigData.Var, value: bool,\n+                     cond: KconfigData.Expr | None = None) -> None:\n             KconfigData.Clause.__init__(self, dest)\n             self.value = value\n             self.cond = cond\n             if self.cond is not None:\n                 self.cond.add_edges_to(self.dest)\n-        def __str__(self):\n+        def __str__(self) -> str:\n             value = 'y' if self.value else 'n'\n             if self.cond is None:\n                 return \"config %s default %s\" % (self.dest, value)\n             else:\n                 return \"config %s default %s if %s\" % (self.dest, value, self.cond)\n \n-        def priority(self):\n+        def priority(self) -> int:\n             # Defaults are processed just before leaving the variable\n             return -1\n-        def process(self):\n+        def process(self) -> None:\n             if not self.dest.has_value() and \\\n                     (self.cond is None or self.cond.evaluate()):\n                 self.dest.set_value(self.value, self)\n \n     class DependsOnClause(Clause):\n-        def __init__(self, dest, expr):\n+        def __init__(self, dest: KconfigData.Var, expr: KconfigData.Expr) -> None:\n             KconfigData.Clause.__init__(self, dest)\n             self.expr = expr\n             self.expr.add_edges_to(self.dest)\n-        def __str__(self):\n+        def __str__(self) -> str:\n             return \"config %s depends on %s\" % (self.dest, self.expr)\n \n-        def process(self):\n+        def process(self) -> None:\n             if not self.expr.evaluate():\n                 self.dest.set_value(False, self)\n \n     class SelectClause(Clause):\n-        def __init__(self, dest, cond):\n+        def __init__(self, dest: KconfigData.Var, cond: KconfigData.Expr) -> None:\n             KconfigData.Clause.__init__(self, dest)\n             self.cond = cond\n             self.cond.add_edges_to(self.dest)\n-        def __str__(self):\n+        def __str__(self) -> str:\n             return \"select %s if %s\" % (self.dest, self.cond)\n \n-        def process(self):\n+        def process(self) -> None:\n             if self.cond.evaluate():\n                 self.dest.set_value(True, self)\n \n-    def __init__(self, value_mangler=defconfig):\n+    def __init__(self, value_mangler: Mangler = defconfig) -> None:\n         self.value_mangler = value_mangler\n-        self.previously_included = []\n-        self.defined_vars = set()\n-        self.referenced_vars = dict()\n-        self.clauses = list()\n+        self.previously_included: list[str] = []\n+        self.defined_vars: set[str] = set()\n+        self.referenced_vars: dict[str, KconfigData.Var] = {}\n+        self.clauses: list[KconfigData.Clause] = []\n \n     # semantic analysis -------------\n \n-    def check_undefined(self):\n+    def check_undefined(self) -> bool:\n         undef = False\n         for i in self.referenced_vars:\n             if i not in self.defined_vars:\n@@ -235,7 +243,7 @@ def check_undefined(self):\n                 undef = True\n         return undef\n \n-    def compute_config(self):\n+    def compute_config(self) -> dict[str, bool]:\n         if self.check_undefined():\n             raise KconfigDataError(\"there were undefined symbols\")\n \n@@ -248,10 +256,10 @@ def compute_config(self):\n             debug_print(source, \"->\", [str(x) for x in edges.outgoing])\n \n         # The reverse of the depth-first order is the topological sort\n-        dfo = dict()\n-        visited = set()\n+        dfo: dict[KconfigData.Var, int] = {}\n+        visited: set[KconfigData.Var] = set()\n         debug_print(\"\\n\")\n-        def visit_fn(var):\n+        def visit_fn(var: KconfigData.Var) -> None:\n             debug_print(var, \"has DFS number\", len(dfo))\n             dfo[var] = len(dfo)\n \n@@ -270,7 +278,7 @@ def visit_fn(var):\n             clause.process()\n \n         debug_print(\"\")\n-        values = dict()\n+        values: dict[str, bool] = {}\n         for name, v in self.referenced_vars.items():\n             debug_print(\"Evaluating\", name)\n             values[name] = v.evaluate()\n@@ -279,39 +287,42 @@ def visit_fn(var):\n \n     # semantic actions -------------\n \n-    def do_declaration(self, var):\n+    def do_declaration(self, var: KconfigData.Var) -> None:\n         if var.name in self.defined_vars:\n             raise KconfigDataError('variable \"%s\" defined twice' % var.name)\n-\n         self.defined_vars.add(var.name)\n \n     # var is a string with the variable's name.\n-    def do_var(self, var):\n+    def do_var(self, var: str) -> KconfigData.Var:\n         if var in self.referenced_vars:\n             return self.referenced_vars[var]\n \n         var_obj = self.referenced_vars[var] = KconfigData.Var(var)\n         return var_obj\n \n-    def do_assignment(self, var, val):\n+    def do_assignment(self, var: KconfigData.Var, val: bool) -> None:\n         self.clauses.append(KconfigData.AssignmentClause(var, val))\n \n-    def do_cmdline_assignment(self, var, val):\n+    def do_cmdline_assignment(self, var: str, val: bool) -> None:\n         assert var.startswith(\"CONFIG_\")\n         self.do_assignment(self.do_var(var[7:]), val)\n \n-    def do_default(self, var, val, cond=None):\n+    def do_default(self, var: KconfigData.Var, val: bool,\n+                   cond: KconfigData.Expr | None = None) -> None:\n         val = self.value_mangler(val)\n         self.clauses.append(KconfigData.DefaultClause(var, val, cond))\n \n-    def do_depends_on(self, var, expr):\n+    def do_depends_on(self, var: KconfigData.Var,\n+                      expr: KconfigData.Expr) -> None:\n         self.clauses.append(KconfigData.DependsOnClause(var, expr))\n \n-    def do_select(self, var, symbol, cond=None):\n+    def do_select(self, var: KconfigData.Var, symbol: KconfigData.Var,\n+                  cond: KconfigData.Expr | None = None) -> None:\n         cond = (cond & var) if cond is not None else var\n         self.clauses.append(KconfigData.SelectClause(symbol, cond))\n \n-    def do_imply(self, var, symbol, cond=None):\n+    def do_imply(self, var: KconfigData.Var, symbol: KconfigData.Var,\n+                 cond: KconfigData.Expr | None = None) -> None:\n         # \"config X imply Y [if COND]\" is the same as\n         # \"config Y default y if X [&& COND]\"\n         cond = (cond & var) if cond is not None else var\n@@ -323,7 +334,7 @@ def do_imply(self, var, symbol, cond=None):\n # -------------------------------------------\n \n # tokens table\n-TOKENS = {}\n+TOKENS: dict[int, str] = {}\n TOK_NONE = -1\n TOK_LPAREN = 0;   TOKENS[TOK_LPAREN] = '\"(\"'\n TOK_RPAREN = 1;   TOKENS[TOK_RPAREN] = '\")\"'\n@@ -346,7 +357,8 @@ def do_imply(self, var, symbol, cond=None):\n TOK_EOF = 18;     TOKENS[TOK_EOF] = 'end of file'\n \n class KconfigParserError(Exception):\n-    def __init__(self, parser, msg, tok=None):\n+    def __init__(self, parser: KconfigParser, msg: str,\n+                 tok: int | str | None = None) -> None:\n         self.loc = parser.location()\n         tok = tok if tok is not None else parser.tok\n         if tok != TOK_NONE:\n@@ -354,33 +366,37 @@ def __init__(self, parser, msg, tok=None):\n             msg = '%s before %s' % (msg, location)\n         self.msg = msg\n \n-    def __str__(self):\n+    def __str__(self) -> str:\n         return \"%s: %s\" % (self.loc, self.msg)\n \n class KconfigParser:\n \n     @classmethod\n-    def parse(cls, fp, data, incl_info=None):\n+    def parse(cls, fp: T.TextIO, data: KconfigData, incl_info: IncludeInfo | None = None) -> None:\n         cls(fp, data, incl_info).parse_config()\n \n-    def __init__(self, fp, data, incl_info):\n+    def __init__(self, fp: T.TextIO, data: KconfigData, incl_info: IncludeInfo | None = None):\n         self.data = data\n         self.incl_info = incl_info\n         self.abs_fname = os.path.abspath(fp.name)\n         self.fname = fp.name\n         self.data.previously_included.append(self.abs_fname)\n+\n         src = fp.read()\n         if src == '' or src[-1] != '\\n':\n             src += '\\n'\n         self.src = src\n-        self.cursor = 0\n-        self.line = 1\n-        self.line_pos = 0\n+        self.cursor: int = 0\n+        self.line: int = 1\n+        self.line_pos: int = 0\n+        self.pos: int = 0\n+        self.tok: int = TOK_NONE\n+        self.val: str | None = None\n         self.get_token()\n \n     # file management -----\n \n-    def location(self):\n+    def location(self) -> str:\n         col = 1\n         for ch in self.src[self.line_pos:self.pos]:\n             if ch == '\\t':\n@@ -391,7 +407,7 @@ def location(self):\n         incl_chain = inf.error_path() if inf is not None else \"\"\n         return '%s%s:%d:%d' % (incl_chain, self.fname, self.line, col)\n \n-    def do_include(self, include):\n+    def do_include(self, include: str) -> None:\n         incl_abs_fname = os.path.join(os.path.dirname(self.abs_fname),\n                                       include)\n         # catch inclusion cycle\n@@ -419,7 +435,7 @@ def do_include(self, include):\n     # recursive descent parser -----\n \n     # y_or_n: Y | N\n-    def parse_y_or_n(self):\n+    def parse_y_or_n(self) -> bool:\n         if self.tok == TOK_Y:\n             self.get_token()\n             return True\n@@ -429,7 +445,7 @@ def parse_y_or_n(self):\n         raise KconfigParserError(self, 'Expected \"y\" or \"n\"')\n \n     # var: ID\n-    def parse_var(self):\n+    def parse_var(self) -> KconfigData.Var:\n         if self.tok != TOK_ID:\n             raise KconfigParserError(self, 'Expected identifier')\n         val = self.val\n@@ -438,7 +454,7 @@ def parse_var(self):\n         return self.data.do_var(val)\n \n     # assignment_var: ID (starting with \"CONFIG_\")\n-    def parse_assignment_var(self):\n+    def parse_assignment_var(self) -> KconfigData.Var:\n         if self.tok != TOK_ID:\n             raise KconfigParserError(self, 'Expected identifier')\n         val = self.val\n@@ -450,7 +466,7 @@ def parse_assignment_var(self):\n         return self.data.do_var(val[7:])\n \n     # assignment: var EQUAL y_or_n\n-    def parse_assignment(self):\n+    def parse_assignment(self) -> None:\n         var = self.parse_assignment_var()\n         if self.tok != TOK_EQUAL:\n             raise KconfigParserError(self, 'Expected \"=\"')\n@@ -460,7 +476,7 @@ def parse_assignment(self):\n     # primary: NOT primary\n     #       | LPAREN expr RPAREN\n     #       | var\n-    def parse_primary(self):\n+    def parse_primary(self) -> KconfigData.Expr:\n         if self.tok == TOK_NOT:\n             self.get_token()\n             val = ~self.parse_primary()\n@@ -477,7 +493,7 @@ def parse_primary(self):\n         return val\n \n     # disj: primary (OR primary)*\n-    def parse_disj(self):\n+    def parse_disj(self) -> KconfigData.Expr:\n         lhs = self.parse_primary()\n         while self.tok == TOK_OR:\n             self.get_token()\n@@ -485,7 +501,7 @@ def parse_disj(self):\n         return lhs\n \n     # expr: disj (AND disj)*\n-    def parse_expr(self):\n+    def parse_expr(self) -> KconfigData.Expr:\n         lhs = self.parse_disj()\n         while self.tok == TOK_AND:\n             self.get_token()\n@@ -494,7 +510,7 @@ def parse_expr(self):\n \n     # condition: IF expr\n     #       | empty\n-    def parse_condition(self):\n+    def parse_condition(self) -> KconfigData.Expr | None:\n         if self.tok != TOK_IF:\n             return None\n         self.get_token()\n@@ -504,7 +520,7 @@ def parse_condition(self):\n     #       | DEPENDS ON expr\n     #       | SELECT var condition\n     #       | BOOL\n-    def parse_property(self, var):\n+    def parse_property(self, var: KconfigData.Var) -> None:\n         if self.tok == TOK_DEFAULT:\n             self.get_token()\n             val = self.parse_y_or_n()\n@@ -533,7 +549,7 @@ def parse_property(self, var):\n \n     # properties: properties property\n     #       | /* empty */\n-    def parse_properties(self, var):\n+    def parse_properties(self, var: KconfigData.Var) -> None:\n         while self.tok == TOK_DEFAULT or self.tok == TOK_DEPENDS or \\\n               self.tok == TOK_SELECT or self.tok == TOK_BOOL or \\\n               self.tok == TOK_IMPLY:\n@@ -546,7 +562,7 @@ def parse_properties(self, var):\n                     + '\"default\", \"depends on\", \"imply\" or \"select\"')\n \n     # declaration: config var properties\n-    def parse_declaration(self):\n+    def parse_declaration(self) -> None:\n         if self.tok == TOK_CONFIG:\n             self.get_token()\n             var = self.parse_var()\n@@ -558,9 +574,10 @@ def parse_declaration(self):\n     # clause: SOURCE\n     #       | declaration\n     #       | assignment\n-    def parse_clause(self):\n+    def parse_clause(self) -> None:\n         if self.tok == TOK_SOURCE:\n             val = self.val\n+            assert val is not None\n             self.get_token()\n             self.do_include(val)\n         elif self.tok == TOK_CONFIG:\n@@ -571,14 +588,15 @@ def parse_clause(self):\n             raise KconfigParserError(self, 'expected \"source\", \"config\" or identifier')\n \n     # config: clause+ EOF\n-    def parse_config(self):\n+    def parse_config(self) -> KconfigData:\n         while self.tok != TOK_EOF:\n             self.parse_clause()\n         return self.data\n \n     # scanner -----\n \n-    def get_token(self):\n+    def get_token(self) -> None:\n+        assert self.src is not None\n         while True:\n             ch = self.src[self.cursor]\n             self.pos = self.cursor\n@@ -590,7 +608,8 @@ def get_token(self):\n                 self.tok = tok\n                 return\n \n-    def check_keyword(self, rest):\n+    def check_keyword(self, rest: str) -> bool:\n+        assert self.src is not None\n         if not self.src.startswith(rest, self.cursor):\n             return False\n         length = len(rest)\n@@ -599,7 +618,8 @@ def check_keyword(self, rest):\n         self.cursor += length\n         return True\n \n-    def scan_token(self, ch):\n+    def scan_token(self, ch: str) -> int | None:\n+        assert self.src is not None\n         if ch == '#':\n             self.cursor = self.src.find('\\n', self.cursor)\n             return None\n@@ -667,7 +687,7 @@ def scan_token(self, ch):\n \n def main():\n     argv = sys.argv\n-    mode = defconfig\n+    mode: Mangler = defconfig\n     if len(sys.argv) > 1:\n         if argv[1] == '--defconfig':\n             del argv[1]\n@@ -691,7 +711,7 @@ def main():\n         sys.exit(1)\n \n     data = KconfigData(mode)\n-    external_vars = set()\n+    external_vars: set[str] = set()\n     for arg in argv[3:]:\n         m = re.match(r'^(CONFIG_[A-Z0-9_]+)=([yn]?)$', arg)\n         if m is not None:\n",
    "prefixes": [
        "13/13"
    ]
}