From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822431; cv=none; d=zohomail.com; s=zohoarc; b=etI3MAKNstoIdcsmAqus2jx43gXLhtxKd/OL/5O4FF/q/lmE3QjAKAFhOvdANx+gN5UzfJR84tUq3uiC7n2kIlLBwh2oEo/CUM7Er+RU5gI7M+GGfSZhKVlz1H906mZZO1iunDYrPtQ6cHobNklf1vwzV4VRuzggjNm7CSE1LKI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822431; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=evJyZ+aBqC9dhQfTQisovrdTrGIIdt7LOPFQO9w8I+c=; b=lgVoOfI88FkPrgEsaWc6gYRdLjiiawSdQZS/oH9ggMlUW/IgjF6d6YMdOBcRYNQ0Uw7oBCXLLIKQ2ropIPe6f4NRM2uhtOHQNSYVWtDsZR3Gp92BroN/rhg4fCNHCmt0BE+3WrbrswWcS/X3ravfPf+tqox+EkOBRzuGl9vJY44= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822431868278.03996764847795; Tue, 7 Feb 2023 18:13:51 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxS-0002jY-Kb; Tue, 07 Feb 2023 21:13:14 -0500 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 1pPZxR-0002il-Aj for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:13 -0500 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 1pPZxP-00040k-FJ for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:13 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-558-aGWUegSVNI2r1tzrtQs99A-1; Tue, 07 Feb 2023 21:13:07 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BBDFB80D0E2; Wed, 8 Feb 2023 02:13:06 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 848981121314; Wed, 8 Feb 2023 02:13:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822390; 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=evJyZ+aBqC9dhQfTQisovrdTrGIIdt7LOPFQO9w8I+c=; b=LGqxVvMjiWfZdmFAzdzVmLEmdZDjYJQz8Nvyn7qvKFkCTtISVTcte4Cfj0kDmuXoWbo7Ul eM0LI2Nd45YtYFu+TKd6YsFVtSA8Wvbq/nuOAY50k5dxUo2IDltHWQI0gTdGXKUJQQ0NsC x9nZcboY4Q65ZqUPeGn7FAXGX1NCtDA= X-MC-Unique: aGWUegSVNI2r1tzrtQs99A-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 1/7] qapi/expr: Split check_expr out from check_exprs Date: Tue, 7 Feb 2023 21:13:00 -0500 Message-Id: <20230208021306.870657-2-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822433914100007 Content-Type: text/plain; charset="utf-8" Primarily, this reduces a nesting level of a particularly long block. It's mostly code movement, but a new docstring is created. It also has the effect of creating a fairly convenient "catch point" in check_exprs for exception handling without making the nesting level even worse. Signed-off-by: John Snow --- This patch was originally written as part of my effort to factor out QAPISourceInfo from this file by having expr.py raise a simple exception, then catch and wrap it at the higher level. This series doesn't do that anymore, but reducing the nesting level still seemed subjectively nice. It's not crucial. Signed-off-by: John Snow --- scripts/qapi/expr.py | 179 +++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 84 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 5a1782b57ea..d01543006d8 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -595,6 +595,99 @@ def check_event(expr: _JSONObject, info: QAPISourceInf= o) -> None: check_type(args, info, "'data'", allow_dict=3Dnot boxed) =20 =20 +def check_expr(expr_elem: _JSONObject) -> None: + """ + Validate and normalize a parsed QAPI schema expression. + + :param expr_elem: The parsed expression to normalize and validate. + + :raise QAPISemError: When this expression fails validation. + :return: None, ``expr`` is normalized in-place as needed. + """ + # Expression + assert isinstance(expr_elem['expr'], dict) + for key in expr_elem['expr'].keys(): + assert isinstance(key, str) + expr: _JSONObject =3D expr_elem['expr'] + + # QAPISourceInfo + assert isinstance(expr_elem['info'], QAPISourceInfo) + info: QAPISourceInfo =3D expr_elem['info'] + + # Optional[QAPIDoc] + tmp =3D expr_elem.get('doc') + assert tmp is None or isinstance(tmp, QAPIDoc) + doc: Optional[QAPIDoc] =3D tmp + + if 'include' in expr: + return + + metas =3D expr.keys() & {'enum', 'struct', 'union', 'alternate', + 'command', 'event'} + if len(metas) !=3D 1: + raise QAPISemError( + info, + "expression must have exactly one key" + " 'enum', 'struct', 'union', 'alternate'," + " 'command', 'event'") + meta =3D metas.pop() + + check_name_is_str(expr[meta], info, "'%s'" % meta) + name =3D cast(str, expr[meta]) + info.set_defn(meta, name) + check_defn_name_str(name, info, meta) + + if doc: + if doc.symbol !=3D name: + raise QAPISemError( + info, "documentation comment is for '%s'" % doc.symbol) + doc.check_expr(expr) + elif info.pragma.doc_required: + raise QAPISemError(info, + "documentation comment required") + + if meta =3D=3D 'enum': + check_keys(expr, info, meta, + ['enum', 'data'], ['if', 'features', 'prefix']) + check_enum(expr, info) + elif meta =3D=3D 'union': + check_keys(expr, info, meta, + ['union', 'base', 'discriminator', 'data'], + ['if', 'features']) + normalize_members(expr.get('base')) + normalize_members(expr['data']) + check_union(expr, info) + elif meta =3D=3D 'alternate': + check_keys(expr, info, meta, + ['alternate', 'data'], ['if', 'features']) + normalize_members(expr['data']) + check_alternate(expr, info) + elif meta =3D=3D 'struct': + check_keys(expr, info, meta, + ['struct', 'data'], ['base', 'if', 'features']) + normalize_members(expr['data']) + check_struct(expr, info) + elif meta =3D=3D 'command': + check_keys(expr, info, meta, + ['command'], + ['data', 'returns', 'boxed', 'if', 'features', + 'gen', 'success-response', 'allow-oob', + 'allow-preconfig', 'coroutine']) + normalize_members(expr.get('data')) + check_command(expr, info) + elif meta =3D=3D 'event': + check_keys(expr, info, meta, + ['event'], ['data', 'boxed', 'if', 'features']) + normalize_members(expr.get('data')) + check_event(expr, info) + else: + assert False, 'unexpected meta type' + + check_if(expr, info, meta) + check_features(expr.get('features'), info) + check_flags(expr, info) + + def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]: """ Validate and normalize a list of parsed QAPI schema expressions. @@ -607,88 +700,6 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSO= NObject]: :raise QAPISemError: When any expression fails validation. :return: The same list of expressions (now modified). """ - for expr_elem in exprs: - # Expression - assert isinstance(expr_elem['expr'], dict) - for key in expr_elem['expr'].keys(): - assert isinstance(key, str) - expr: _JSONObject =3D expr_elem['expr'] - - # QAPISourceInfo - assert isinstance(expr_elem['info'], QAPISourceInfo) - info: QAPISourceInfo =3D expr_elem['info'] - - # Optional[QAPIDoc] - tmp =3D expr_elem.get('doc') - assert tmp is None or isinstance(tmp, QAPIDoc) - doc: Optional[QAPIDoc] =3D tmp - - if 'include' in expr: - continue - - metas =3D expr.keys() & {'enum', 'struct', 'union', 'alternate', - 'command', 'event'} - if len(metas) !=3D 1: - raise QAPISemError( - info, - "expression must have exactly one key" - " 'enum', 'struct', 'union', 'alternate'," - " 'command', 'event'") - meta =3D metas.pop() - - check_name_is_str(expr[meta], info, "'%s'" % meta) - name =3D cast(str, expr[meta]) - info.set_defn(meta, name) - check_defn_name_str(name, info, meta) - - if doc: - if doc.symbol !=3D name: - raise QAPISemError( - info, "documentation comment is for '%s'" % doc.symbol) - doc.check_expr(expr) - elif info.pragma.doc_required: - raise QAPISemError(info, - "documentation comment required") - - if meta =3D=3D 'enum': - check_keys(expr, info, meta, - ['enum', 'data'], ['if', 'features', 'prefix']) - check_enum(expr, info) - elif meta =3D=3D 'union': - check_keys(expr, info, meta, - ['union', 'base', 'discriminator', 'data'], - ['if', 'features']) - normalize_members(expr.get('base')) - normalize_members(expr['data']) - check_union(expr, info) - elif meta =3D=3D 'alternate': - check_keys(expr, info, meta, - ['alternate', 'data'], ['if', 'features']) - normalize_members(expr['data']) - check_alternate(expr, info) - elif meta =3D=3D 'struct': - check_keys(expr, info, meta, - ['struct', 'data'], ['base', 'if', 'features']) - normalize_members(expr['data']) - check_struct(expr, info) - elif meta =3D=3D 'command': - check_keys(expr, info, meta, - ['command'], - ['data', 'returns', 'boxed', 'if', 'features', - 'gen', 'success-response', 'allow-oob', - 'allow-preconfig', 'coroutine']) - normalize_members(expr.get('data')) - check_command(expr, info) - elif meta =3D=3D 'event': - check_keys(expr, info, meta, - ['event'], ['data', 'boxed', 'if', 'features']) - normalize_members(expr.get('data')) - check_event(expr, info) - else: - assert False, 'unexpected meta type' - - check_if(expr, info, meta) - check_features(expr.get('features'), info) - check_flags(expr, info) - + for expr in exprs: + check_expr(expr) return exprs --=20 2.39.0 From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822433; cv=none; d=zohomail.com; s=zohoarc; b=RcrbD6plG4JlgUWYs0eIqVY2odrlGk08y9jUwJ2hbxmZuWedOm2P04ftC2+PPtre/67cRhWYpaHhKfQjDN3UIQkYfhxI/jMuI1xIoLyFRpLHOCu3dyNuaH7rXTag/D+jVYafttzTQE5Mgj8980oIhg29mFXOJanSYkrBYKK+XD4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822433; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=IaGt8FOIU5ACxtWhwo5F9XWVv9j/MS6Ra5YEusjn62U=; b=HwuOzIaiWcCLESiYAWkMMAOT8dbb7U9i/NUJnHktXiS1kYQqm8y7daGPvWfueBa9EtvdDx9jrb2/TFzh8EldwTZ3pMwGd9xjWRcGESIr4K9QsPEml9XGvqPAOJTpX/D6E3fSNa15JO/fhIJP1UzmQ8lN/2orr14ERYhJkW74n6E= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822433248551.1015359806706; Tue, 7 Feb 2023 18:13:53 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxQ-0002iO-Lr; Tue, 07 Feb 2023 21:13:12 -0500 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 1pPZxP-0002hp-Lh for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:11 -0500 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 1pPZxN-00040F-CU for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:11 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-91-ziG7_NpZNN2cmf7pjYFWWA-1; Tue, 07 Feb 2023 21:13:07 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 05854884341; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id CA7931121314; Wed, 8 Feb 2023 02:13:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822388; 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=IaGt8FOIU5ACxtWhwo5F9XWVv9j/MS6Ra5YEusjn62U=; b=hoGmlhU17e0tiLbWX6gKIpd/HgLTNr4QuEVE5Q1Hn0lUHqk7QTmpcwSvFsS4HWYot1GHas aPYSIsYqpmAh+cU3QvLbJVHGQ4i0uRMHZabRPF7H/44SdyZg/yfTQbldMs7RHszWhXzWAq kAsZz119Q1bYT8nRt7bk9y/zYdnE7DE= X-MC-Unique: ziG7_NpZNN2cmf7pjYFWWA-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 2/7] qapi/parser.py: add ParsedExpression type Date: Tue, 7 Feb 2023 21:13:01 -0500 Message-Id: <20230208021306.870657-3-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822433907100006 Content-Type: text/plain; charset="utf-8" This is an immutable, named, typed tuple. It's arguably nicer than arbitrary dicts for passing data around when using strict typing. This patch turns parser.exprs into a list of ParsedExpressions instead, and adjusts expr.py to match. This allows the types we specify in parser.py to be "remembered" all the way through expr.py and into schema.py. Several assertions around packing and unpacking this data can be removed as a result. Signed-off-by: John Snow --- scripts/qapi/expr.py | 29 +++++++++-------------------- scripts/qapi/parser.py | 29 ++++++++++++++++++----------- scripts/qapi/schema.py | 6 +++--- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index d01543006d8..293f830fe9d 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -44,7 +44,7 @@ =20 from .common import c_name from .error import QAPISemError -from .parser import QAPIDoc +from .parser import ParsedExpression from .source import QAPISourceInfo =20 =20 @@ -595,29 +595,17 @@ def check_event(expr: _JSONObject, info: QAPISourceIn= fo) -> None: check_type(args, info, "'data'", allow_dict=3Dnot boxed) =20 =20 -def check_expr(expr_elem: _JSONObject) -> None: +def check_expr(pexpr: ParsedExpression) -> None: """ - Validate and normalize a parsed QAPI schema expression. + Validate and normalize a `ParsedExpression`. =20 - :param expr_elem: The parsed expression to normalize and validate. + :param pexpr: The parsed expression to normalize and validate. =20 :raise QAPISemError: When this expression fails validation. - :return: None, ``expr`` is normalized in-place as needed. + :return: None, ``pexpr`` is normalized in-place as needed. """ - # Expression - assert isinstance(expr_elem['expr'], dict) - for key in expr_elem['expr'].keys(): - assert isinstance(key, str) - expr: _JSONObject =3D expr_elem['expr'] - - # QAPISourceInfo - assert isinstance(expr_elem['info'], QAPISourceInfo) - info: QAPISourceInfo =3D expr_elem['info'] - - # Optional[QAPIDoc] - tmp =3D expr_elem.get('doc') - assert tmp is None or isinstance(tmp, QAPIDoc) - doc: Optional[QAPIDoc] =3D tmp + expr =3D pexpr.expr + info =3D pexpr.info =20 if 'include' in expr: return @@ -637,6 +625,7 @@ def check_expr(expr_elem: _JSONObject) -> None: info.set_defn(meta, name) check_defn_name_str(name, info, meta) =20 + doc =3D pexpr.doc if doc: if doc.symbol !=3D name: raise QAPISemError( @@ -688,7 +677,7 @@ def check_expr(expr_elem: _JSONObject) -> None: check_flags(expr, info) =20 =20 -def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]: +def check_exprs(exprs: List[ParsedExpression]) -> List[ParsedExpression]: """ Validate and normalize a list of parsed QAPI schema expressions. =20 diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 1b006cdc133..f897dffbfd4 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -21,6 +21,7 @@ TYPE_CHECKING, Dict, List, + NamedTuple, Optional, Set, Union, @@ -48,6 +49,12 @@ # several modules. =20 =20 +class ParsedExpression(NamedTuple): + expr: TopLevelExpr + info: QAPISourceInfo + doc: Optional['QAPIDoc'] + + class QAPIParseError(QAPISourceError): """Error class for all QAPI schema parsing errors.""" def __init__(self, parser: 'QAPISchemaParser', msg: str): @@ -100,7 +107,7 @@ def __init__(self, self.line_pos =3D 0 =20 # Parser output: - self.exprs: List[Dict[str, object]] =3D [] + self.exprs: List[ParsedExpression] =3D [] self.docs: List[QAPIDoc] =3D [] =20 # Showtime! @@ -147,8 +154,7 @@ def _parse(self) -> None: "value of 'include' must be a strin= g") incl_fname =3D os.path.join(os.path.dirname(self._fname), include) - self.exprs.append({'expr': {'include': incl_fname}, - 'info': info}) + self._add_expr(OrderedDict({'include': incl_fname}), info) exprs_include =3D self._include(include, info, incl_fname, self._included) if exprs_include: @@ -165,17 +171,18 @@ def _parse(self) -> None: for name, value in pragma.items(): self._pragma(name, value, info) else: - expr_elem =3D {'expr': expr, - 'info': info} - if cur_doc: - if not cur_doc.symbol: - raise QAPISemError( - cur_doc.info, "definition documentation requir= ed") - expr_elem['doc'] =3D cur_doc - self.exprs.append(expr_elem) + if cur_doc and not cur_doc.symbol: + raise QAPISemError( + cur_doc.info, "definition documentation required") + self._add_expr(expr, info, cur_doc) cur_doc =3D None self.reject_expr_doc(cur_doc) =20 + def _add_expr(self, expr: TopLevelExpr, + info: QAPISourceInfo, + doc: Optional['QAPIDoc'] =3D None) -> None: + self.exprs.append(ParsedExpression(expr, info, doc)) + @staticmethod def reject_expr_doc(doc: Optional['QAPIDoc']) -> None: if doc and doc.symbol: diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index cd8661125cd..89f8e60db36 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -1168,9 +1168,9 @@ def _def_event(self, expr, info, doc): =20 def _def_exprs(self, exprs): for expr_elem in exprs: - expr =3D expr_elem['expr'] - info =3D expr_elem['info'] - doc =3D expr_elem.get('doc') + expr =3D expr_elem.expr + info =3D expr_elem.info + doc =3D expr_elem.doc if 'enum' in expr: self._def_enum_type(expr, info, doc) elif 'struct' in expr: --=20 2.39.0 From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822456; cv=none; d=zohomail.com; s=zohoarc; b=iH7uRfJqssNb7qEypNKkh4gN3owTdXbQaWZq0m1dBx1pzrH4xJUDVgk5w2EP8sw0QnIB+54mq0iOBTefOzG9bqMh2ruLFmNikLnMkkztJOTdC4xPnYH7t1k3G7CidO/ukpY91DGuf3Q1F07IsbNf92ggfd9uCpeB0bEGaFNKmfk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822456; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=FJpMAPmup+OzFzYUIcSQ1E0AC85PvH7xKpNHcGZb5qM=; b=fX8YkqqZuo13taJnK6URFC4DgB/1jqNWud3ZFSDZf1UitymqhR/4zXoImnsAB2rjm9wkv2MOgvOtKBaRfOL97YUgEEh85eTb1Qc/R07fCqFVjDP9QzCdDsvuR3mtMOZCy7GQbDgi7rdOsUT0JJA+h3wYNmMdjUql4eQoM2YiIKM= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822456629579.0594141714787; Tue, 7 Feb 2023 18:14:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxS-0002jU-Dc; Tue, 07 Feb 2023 21:13:14 -0500 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 1pPZxQ-0002iU-Qp for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:12 -0500 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 1pPZxO-00040Q-7n for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:12 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-59-_zdb9GwzOuuohp5DavAxKA-1; Tue, 07 Feb 2023 21:13:07 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 408F21C29D4A; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1314D1121314; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822389; 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=FJpMAPmup+OzFzYUIcSQ1E0AC85PvH7xKpNHcGZb5qM=; b=PCLOfMav/WksjjTh82RzG7AxP1ImDPBNcbQ+sa9ZuY/H30CvqPAAK1SIAyQm0xs/hf76oR Yi//ib5ppMCmPzepu43z24nduh60nvIQITmGhPWfKBJ1NrmJPbCPwJkxCVAOfbgE38Spvq SCDVTgO98ZRLOLcYEnsIh3TVAsWd7eU= X-MC-Unique: _zdb9GwzOuuohp5DavAxKA-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 3/7] qapi/expr: Use TopLevelExpr where appropriate Date: Tue, 7 Feb 2023 21:13:02 -0500 Message-Id: <20230208021306.870657-4-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822457835100003 Content-Type: text/plain; charset="utf-8" Remove most usages of _JSONObject with a more semantically meaningful alias. Note that this is only a semantic alias; the distinction is not enforced by the type system. This is merely a benefit for the human: instead of check_xyz functions operating on a representation of some "JSON Object", we can document them as operating on QAPI's Top Level Expressions directly; it's more semantically meaningful. Signed-off-by: John Snow --- scripts/qapi/expr.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 293f830fe9d..338c9ea4131 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -44,7 +44,7 @@ =20 from .common import c_name from .error import QAPISemError -from .parser import ParsedExpression +from .parser import ParsedExpression, TopLevelExpr from .source import QAPISourceInfo =20 =20 @@ -229,11 +229,11 @@ def pprint(elems: Iterable[str]) -> str: pprint(unknown), pprint(allowed))) =20 =20 -def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_flags(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ Ensure flag members (if present) have valid values. =20 - :param expr: The expression to validate. + :param expr: The `TopLevelExpr` to validate. :param info: QAPI schema source file information. =20 :raise QAPISemError: @@ -447,9 +447,9 @@ def check_features(features: Optional[object], check_if(feat, info, source) =20 =20 -def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_enum(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ - Normalize and validate this expression as an ``enum`` definition. + Normalize and validate this `TopLevelExpr` as an ``enum`` definition. =20 :param expr: The expression to validate. :param info: QAPI schema source file information. @@ -486,9 +486,9 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo)= -> None: check_features(member.get('features'), info) =20 =20 -def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_struct(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ - Normalize and validate this expression as a ``struct`` definition. + Normalize and validate this `TopLevelExpr` as a ``struct`` definition. =20 :param expr: The expression to validate. :param info: QAPI schema source file information. @@ -503,9 +503,9 @@ def check_struct(expr: _JSONObject, info: QAPISourceInf= o) -> None: check_type(expr.get('base'), info, "'base'") =20 =20 -def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_union(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ - Normalize and validate this expression as a ``union`` definition. + Normalize and validate this `TopLevelExpr` as a ``union`` definition. =20 :param expr: The expression to validate. :param info: QAPI schema source file information. @@ -531,9 +531,9 @@ def check_union(expr: _JSONObject, info: QAPISourceInfo= ) -> None: check_type(value['type'], info, source, allow_array=3Dnot base) =20 =20 -def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_alternate(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ - Normalize and validate this expression as an ``alternate`` definition. + Normalize and validate this `TopLevelExpr` as an ``alternate`` definit= ion. =20 :param expr: The expression to validate. :param info: QAPI schema source file information. @@ -557,9 +557,9 @@ def check_alternate(expr: _JSONObject, info: QAPISource= Info) -> None: check_type(value['type'], info, source, allow_array=3DTrue) =20 =20 -def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_command(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ - Normalize and validate this expression as a ``command`` definition. + Normalize and validate this `TopLevelExpr` as a ``command`` definition. =20 :param expr: The expression to validate. :param info: QAPI schema source file information. @@ -577,9 +577,9 @@ def check_command(expr: _JSONObject, info: QAPISourceIn= fo) -> None: check_type(rets, info, "'returns'", allow_array=3DTrue) =20 =20 -def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None: +def check_event(expr: TopLevelExpr, info: QAPISourceInfo) -> None: """ - Normalize and validate this expression as an ``event`` definition. + Normalize and validate this `TopLevelExpr` as an ``event`` definition. =20 :param expr: The expression to validate. :param info: QAPI schema source file information. --=20 2.39.0 From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822472; cv=none; d=zohomail.com; s=zohoarc; b=YNbsJ5HBgCg7g5A2vWFpYdKIfMluUT4/8qP4fHONZRAhoAyZhiImnN1UudVrJVm+Dmo0PV/iwjLj55Q2zWZ7H90hQNqX9q+q0iVgz5UFU3z9wECTDwhu0UJpqCpSMG3QyQJcdWliVqt0hKeLvVMcYHZl51/mMbdFgjg2y2pCMvg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822472; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=r2aZxQLAeUC0cRqiVMBvIYd8dSbo69BJeODYzbqQ5I4=; b=O0x+3Y/+c7FwZmlJRyeOI8WmYVgwW3dB2Ju6LZ8JGUpXS/XBR8w1dqbs7lg71qGE/G7YZStqs7M3GIREDY0yA4CI+LkoxyY3ObrnXm60iwwPBJbWiJrAUXkCxKTMI36MQ2Qf23ByzPMt8RUAeWPNluxVEZ8JispJ+LvPlInaQwY= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822472801347.36634882731903; Tue, 7 Feb 2023 18:14:32 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxT-0002jb-2h; Tue, 07 Feb 2023 21:13:15 -0500 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 1pPZxR-0002j3-LY for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:13 -0500 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 1pPZxP-00040y-VX for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:13 -0500 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-177-dgkJ6yDONoe_5TuScjxkdg-1; Tue, 07 Feb 2023 21:13:07 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7D7033C0DDB7; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4DD921121314; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822391; 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=r2aZxQLAeUC0cRqiVMBvIYd8dSbo69BJeODYzbqQ5I4=; b=P/6fBfpUx7x2OArkILz+6l5/whYyaBlkrCJJhHoIlA5w0x6ve4I9FQIA3II59FWfdOemxd sQvOgqIVHn2cMNaRpCzMYlQXyI1pi8K3PUUEqPAGJ0wu4PV5bNudP3eg0tKbsNK3LiEuts /+wjsgz4G1gpE0PLPotBNWmVgOL9FI0= X-MC-Unique: dgkJ6yDONoe_5TuScjxkdg-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 4/7] qapi/expr: add typing workaround for AbstractSet Date: Tue, 7 Feb 2023 21:13:03 -0500 Message-Id: <20230208021306.870657-5-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822473935100011 Content-Type: text/plain; charset="utf-8" As part of attempting to unify the JSON types, I discovered that mypy believes that `Mapping[str, ...].keys() & Set[str]` produces an `AbstractSet[str]` and not a `Set[str]`. As a result, mypy is unsure if the .pop() is safe. Eh, fine, just wrap the expression in a set() constructor to force it to be a mutable type. Signed-off-by: John Snow --- scripts/qapi/expr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 338c9ea4131..95a25758fed 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -610,8 +610,8 @@ def check_expr(pexpr: ParsedExpression) -> None: if 'include' in expr: return =20 - metas =3D expr.keys() & {'enum', 'struct', 'union', 'alternate', - 'command', 'event'} + metas =3D set(expr.keys() & { + 'enum', 'struct', 'union', 'alternate', 'command', 'event'}) if len(metas) !=3D 1: raise QAPISemError( info, --=20 2.39.0 From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822458; cv=none; d=zohomail.com; s=zohoarc; b=XFyo7+CKaeEeAc8hHzxWH/YuTcB5HRsklptmf5qLDZe6hiS9vUOAgJi3Z2zdIlZWh/X34rtjolS9Mr3ttxkgD6alPDPocfxQ0YHAy2yUEJFVRAk2c0pmqMPaR9qVHntm+lJJpY1+HKpAm8XT7/DkKk6n3o0ZMlhvIPeM41iRf/w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822458; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=C5Ojf+QH3vh2xYLS8rxdwH8CNicyxdd5mtLhrdyqNKI=; b=C5EB9KC1Nx7W0+JsaJ4FBMmgimHIvI5dJvzd438bSSo5Umaw1VjH3Ieykfh5rsq6SMLXKPdTVUF020u3NIn0Dt2G9DAH3SCfRc98xxC2VbJAPHGZHlAN180MZegwZdiO88gUglPAfYUwj19ea2kXXasvxq9QPer+thJP0HRTvp0= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822458855606.1444426599002; Tue, 7 Feb 2023 18:14:18 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxT-0002jd-KO; Tue, 07 Feb 2023 21:13:15 -0500 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 1pPZxS-0002jB-0j for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:14 -0500 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 1pPZxO-00040S-7g for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:13 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-49-wuCuYJzfMRurwFWWyIFvEg-1; Tue, 07 Feb 2023 21:13:08 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C133F101A52E; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8B4B71121314; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822389; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=C5Ojf+QH3vh2xYLS8rxdwH8CNicyxdd5mtLhrdyqNKI=; b=TuOOlic6c0ijDQ+JzWaMIhg/GUcbN+TzFZeLdBCmbXSQyAqn9rV+fEuFxICuxPIyoNDMud ZU0jqEhioFFfzVDaYS0oRNRFWdUptatPPz9YqzRBaZF5CHI8UKps+7gDs5zW8ZSQflmKji E/Y8zxVHH4nioZBZxI9iS+1XXoIJ4Lk= X-MC-Unique: wuCuYJzfMRurwFWWyIFvEg-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 5/7] qapi/parser: [RFC] add QAPIExpression Date: Tue, 7 Feb 2023 21:13:04 -0500 Message-Id: <20230208021306.870657-6-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822459889100001 The idea here is to combine 'TopLevelExpr' and 'ParsedExpression' into one type that accomplishes the purposes of both types; 1. TopLevelExpr is meant to represent a JSON Object, but only those that represent what qapi-schema calls a TOP-LEVEL-EXPR, i.e. definitions, pragmas, and includes. 2. ParsedExpression is meant to represent a container around the above type, alongside QAPI-specific metadata -- the QAPISourceInfo and QAPIDoc objects. We can actually just roll these up into one type: A python mapping that has the metadata embedded directly inside of it. NB: This necessitates a change of typing for check_if() and check_keys(), because mypy does not believe UserDict[str, object] =E2=8A=86 Dict[str, object]. It will, however, accept Mapping or MutableMapping. In this case, the immutable form is preferred as an input parameter because we don't actually mutate the input. Without this change, we will observe: qapi/expr.py:631: error: Argument 1 to "check_keys" has incompatible type "QAPIExpression"; expected "Dict[str, object]" Signed-off-by: John Snow --- scripts/qapi/expr.py | 133 +++++++++++++++++++---------------------- scripts/qapi/parser.py | 43 ++++++++----- scripts/qapi/schema.py | 105 ++++++++++++++++---------------- 3 files changed, 142 insertions(+), 139 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 95a25758fed..83fa7a85b06 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -34,9 +34,9 @@ import re from typing import ( Collection, - Dict, Iterable, List, + Mapping, Optional, Union, cast, @@ -44,7 +44,7 @@ =20 from .common import c_name from .error import QAPISemError -from .parser import ParsedExpression, TopLevelExpr +from .parser import QAPIExpression from .source import QAPISourceInfo =20 =20 @@ -53,7 +53,7 @@ # here (and also not practical as long as mypy lacks recursive # types), because the purpose of this module is to interrogate that # type. -_JSONObject =3D Dict[str, object] +_JSONObject =3D Mapping[str, object] =20 =20 # See check_name_str(), below. @@ -229,12 +229,11 @@ def pprint(elems: Iterable[str]) -> str: pprint(unknown), pprint(allowed))) =20 =20 -def check_flags(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_flags(expr: QAPIExpression) -> None: """ Ensure flag members (if present) have valid values. =20 - :param expr: The `TopLevelExpr` to validate. - :param info: QAPI schema source file information. + :param expr: The `QAPIExpression` to validate. =20 :raise QAPISemError: When certain flags have an invalid value, or when @@ -243,18 +242,18 @@ def check_flags(expr: TopLevelExpr, info: QAPISourceI= nfo) -> None: for key in ('gen', 'success-response'): if key in expr and expr[key] is not False: raise QAPISemError( - info, "flag '%s' may only use false value" % key) + expr.info, "flag '%s' may only use false value" % key) for key in ('boxed', 'allow-oob', 'allow-preconfig', 'coroutine'): if key in expr and expr[key] is not True: raise QAPISemError( - info, "flag '%s' may only use true value" % key) + expr.info, "flag '%s' may only use true value" % key) if 'allow-oob' in expr and 'coroutine' in expr: # This is not necessarily a fundamental incompatibility, but # we don't have a use case and the desired semantics isn't # obvious. The simplest solution is to forbid it until we get # a use case for it. - raise QAPISemError(info, "flags 'allow-oob' and 'coroutine' " - "are incompatible") + raise QAPISemError( + expr.info, "flags 'allow-oob' and 'coroutine' are incompatible= ") =20 =20 def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None: @@ -447,12 +446,11 @@ def check_features(features: Optional[object], check_if(feat, info, source) =20 =20 -def check_enum(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_enum(expr: QAPIExpression) -> None: """ - Normalize and validate this `TopLevelExpr` as an ``enum`` definition. + Normalize and validate this `QAPIExpression` as an ``enum`` definition. =20 :param expr: The expression to validate. - :param info: QAPI schema source file information. =20 :raise QAPISemError: When ``expr`` is not a valid ``enum``. :return: None, ``expr`` is normalized in-place as needed. @@ -462,36 +460,35 @@ def check_enum(expr: TopLevelExpr, info: QAPISourceIn= fo) -> None: prefix =3D expr.get('prefix') =20 if not isinstance(members, list): - raise QAPISemError(info, "'data' must be an array") + raise QAPISemError(expr.info, "'data' must be an array") if prefix is not None and not isinstance(prefix, str): - raise QAPISemError(info, "'prefix' must be a string") + raise QAPISemError(expr.info, "'prefix' must be a string") =20 - permissive =3D name in info.pragma.member_name_exceptions + permissive =3D name in expr.info.pragma.member_name_exceptions =20 members[:] =3D [m if isinstance(m, dict) else {'name': m} for m in members] for member in members: source =3D "'data' member" - check_keys(member, info, source, ['name'], ['if', 'features']) + check_keys(member, expr.info, source, ['name'], ['if', 'features']) member_name =3D member['name'] - check_name_is_str(member_name, info, source) + check_name_is_str(member_name, expr.info, source) source =3D "%s '%s'" % (source, member_name) # Enum members may start with a digit if member_name[0].isdigit(): member_name =3D 'd' + member_name # Hack: hide the digit - check_name_lower(member_name, info, source, + check_name_lower(member_name, expr.info, source, permit_upper=3Dpermissive, permit_underscore=3Dpermissive) - check_if(member, info, source) - check_features(member.get('features'), info) + check_if(member, expr.info, source) + check_features(member.get('features'), expr.info) =20 =20 -def check_struct(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_struct(expr: QAPIExpression) -> None: """ - Normalize and validate this `TopLevelExpr` as a ``struct`` definition. + Normalize and validate this `QAPIExpression` as a ``struct`` definitio= n. =20 :param expr: The expression to validate. - :param info: QAPI schema source file information. =20 :raise QAPISemError: When ``expr`` is not a valid ``struct``. :return: None, ``expr`` is normalized in-place as needed. @@ -499,16 +496,15 @@ def check_struct(expr: TopLevelExpr, info: QAPISource= Info) -> None: name =3D cast(str, expr['struct']) # Checked in check_exprs members =3D expr['data'] =20 - check_type(members, info, "'data'", allow_dict=3Dname) - check_type(expr.get('base'), info, "'base'") + check_type(members, expr.info, "'data'", allow_dict=3Dname) + check_type(expr.get('base'), expr.info, "'base'") =20 =20 -def check_union(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_union(expr: QAPIExpression) -> None: """ - Normalize and validate this `TopLevelExpr` as a ``union`` definition. + Normalize and validate this `QAPIExpression` as a ``union`` definition. =20 :param expr: The expression to validate. - :param info: QAPI schema source file information. =20 :raise QAPISemError: when ``expr`` is not a valid ``union``. :return: None, ``expr`` is normalized in-place as needed. @@ -518,25 +514,24 @@ def check_union(expr: TopLevelExpr, info: QAPISourceI= nfo) -> None: discriminator =3D expr['discriminator'] members =3D expr['data'] =20 - check_type(base, info, "'base'", allow_dict=3Dname) - check_name_is_str(discriminator, info, "'discriminator'") + check_type(base, expr.info, "'base'", allow_dict=3Dname) + check_name_is_str(discriminator, expr.info, "'discriminator'") =20 if not isinstance(members, dict): - raise QAPISemError(info, "'data' must be an object") + raise QAPISemError(expr.info, "'data' must be an object") =20 for (key, value) in members.items(): source =3D "'data' member '%s'" % key - check_keys(value, info, source, ['type'], ['if']) - check_if(value, info, source) - check_type(value['type'], info, source, allow_array=3Dnot base) + check_keys(value, expr.info, source, ['type'], ['if']) + check_if(value, expr.info, source) + check_type(value['type'], expr.info, source, allow_array=3Dnot bas= e) =20 =20 -def check_alternate(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_alternate(expr: QAPIExpression) -> None: """ - Normalize and validate this `TopLevelExpr` as an ``alternate`` definit= ion. + Normalize and validate a `QAPIExpression` as an ``alternate`` definiti= on. =20 :param expr: The expression to validate. - :param info: QAPI schema source file information. =20 :raise QAPISemError: When ``expr`` is not a valid ``alternate``. :return: None, ``expr`` is normalized in-place as needed. @@ -544,25 +539,24 @@ def check_alternate(expr: TopLevelExpr, info: QAPISou= rceInfo) -> None: members =3D expr['data'] =20 if not members: - raise QAPISemError(info, "'data' must not be empty") + raise QAPISemError(expr.info, "'data' must not be empty") =20 if not isinstance(members, dict): - raise QAPISemError(info, "'data' must be an object") + raise QAPISemError(expr.info, "'data' must be an object") =20 for (key, value) in members.items(): source =3D "'data' member '%s'" % key - check_name_lower(key, info, source) - check_keys(value, info, source, ['type'], ['if']) - check_if(value, info, source) - check_type(value['type'], info, source, allow_array=3DTrue) + check_name_lower(key, expr.info, source) + check_keys(value, expr.info, source, ['type'], ['if']) + check_if(value, expr.info, source) + check_type(value['type'], expr.info, source, allow_array=3DTrue) =20 =20 -def check_command(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_command(expr: QAPIExpression) -> None: """ - Normalize and validate this `TopLevelExpr` as a ``command`` definition. + Normalize and validate this `QAPIExpression` as a ``command`` definiti= on. =20 :param expr: The expression to validate. - :param info: QAPI schema source file information. =20 :raise QAPISemError: When ``expr`` is not a valid ``command``. :return: None, ``expr`` is normalized in-place as needed. @@ -572,17 +566,16 @@ def check_command(expr: TopLevelExpr, info: QAPISourc= eInfo) -> None: boxed =3D expr.get('boxed', False) =20 if boxed and args is None: - raise QAPISemError(info, "'boxed': true requires 'data'") - check_type(args, info, "'data'", allow_dict=3Dnot boxed) - check_type(rets, info, "'returns'", allow_array=3DTrue) + raise QAPISemError(expr.info, "'boxed': true requires 'data'") + check_type(args, expr.info, "'data'", allow_dict=3Dnot boxed) + check_type(rets, expr.info, "'returns'", allow_array=3DTrue) =20 =20 -def check_event(expr: TopLevelExpr, info: QAPISourceInfo) -> None: +def check_event(expr: QAPIExpression) -> None: """ - Normalize and validate this `TopLevelExpr` as an ``event`` definition. + Normalize and validate this `QAPIExpression` as an ``event`` definitio= n. =20 :param expr: The expression to validate. - :param info: QAPI schema source file information. =20 :raise QAPISemError: When ``expr`` is not a valid ``event``. :return: None, ``expr`` is normalized in-place as needed. @@ -591,25 +584,23 @@ def check_event(expr: TopLevelExpr, info: QAPISourceI= nfo) -> None: boxed =3D expr.get('boxed', False) =20 if boxed and args is None: - raise QAPISemError(info, "'boxed': true requires 'data'") - check_type(args, info, "'data'", allow_dict=3Dnot boxed) + raise QAPISemError(expr.info, "'boxed': true requires 'data'") + check_type(args, expr.info, "'data'", allow_dict=3Dnot boxed) =20 =20 -def check_expr(pexpr: ParsedExpression) -> None: +def check_expr(expr: QAPIExpression) -> None: """ - Validate and normalize a `ParsedExpression`. + Validate and normalize a `QAPIExpression`. =20 - :param pexpr: The parsed expression to normalize and validate. + :param expr: The parsed expression to normalize and validate. =20 :raise QAPISemError: When this expression fails validation. - :return: None, ``pexpr`` is normalized in-place as needed. + :return: None, ``expr`` is normalized in-place as needed. """ - expr =3D pexpr.expr - info =3D pexpr.info - if 'include' in expr: return =20 + info =3D expr.info metas =3D set(expr.keys() & { 'enum', 'struct', 'union', 'alternate', 'command', 'event'}) if len(metas) !=3D 1: @@ -625,7 +616,7 @@ def check_expr(pexpr: ParsedExpression) -> None: info.set_defn(meta, name) check_defn_name_str(name, info, meta) =20 - doc =3D pexpr.doc + doc =3D expr.doc if doc: if doc.symbol !=3D name: raise QAPISemError( @@ -638,24 +629,24 @@ def check_expr(pexpr: ParsedExpression) -> None: if meta =3D=3D 'enum': check_keys(expr, info, meta, ['enum', 'data'], ['if', 'features', 'prefix']) - check_enum(expr, info) + check_enum(expr) elif meta =3D=3D 'union': check_keys(expr, info, meta, ['union', 'base', 'discriminator', 'data'], ['if', 'features']) normalize_members(expr.get('base')) normalize_members(expr['data']) - check_union(expr, info) + check_union(expr) elif meta =3D=3D 'alternate': check_keys(expr, info, meta, ['alternate', 'data'], ['if', 'features']) normalize_members(expr['data']) - check_alternate(expr, info) + check_alternate(expr) elif meta =3D=3D 'struct': check_keys(expr, info, meta, ['struct', 'data'], ['base', 'if', 'features']) normalize_members(expr['data']) - check_struct(expr, info) + check_struct(expr) elif meta =3D=3D 'command': check_keys(expr, info, meta, ['command'], @@ -663,21 +654,21 @@ def check_expr(pexpr: ParsedExpression) -> None: 'gen', 'success-response', 'allow-oob', 'allow-preconfig', 'coroutine']) normalize_members(expr.get('data')) - check_command(expr, info) + check_command(expr) elif meta =3D=3D 'event': check_keys(expr, info, meta, ['event'], ['data', 'boxed', 'if', 'features']) normalize_members(expr.get('data')) - check_event(expr, info) + check_event(expr) else: assert False, 'unexpected meta type' =20 check_if(expr, info, meta) check_features(expr.get('features'), info) - check_flags(expr, info) + check_flags(expr) =20 =20 -def check_exprs(exprs: List[ParsedExpression]) -> List[ParsedExpression]: +def check_exprs(exprs: List[QAPIExpression]) -> List[QAPIExpression]: """ Validate and normalize a list of parsed QAPI schema expressions. =20 diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index f897dffbfd4..88f6fdfa67b 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -14,14 +14,14 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. =20 -from collections import OrderedDict +from collections import OrderedDict, UserDict import os import re from typing import ( TYPE_CHECKING, Dict, List, - NamedTuple, + Mapping, Optional, Set, Union, @@ -38,21 +38,32 @@ from .schema import QAPISchemaFeature, QAPISchemaMember =20 =20 -#: Represents a single Top Level QAPI schema expression. -TopLevelExpr =3D Dict[str, object] - # Return value alias for get_expr(). _ExprValue =3D Union[List[object], Dict[str, object], str, bool] =20 -# FIXME: Consolidate and centralize definitions for TopLevelExpr, -# _ExprValue, _JSONValue, and _JSONObject; currently scattered across -# several modules. =20 +# FIXME: Consolidate and centralize definitions for _ExprValue, +# JSONValue, and _JSONObject; currently scattered across several +# modules. =20 -class ParsedExpression(NamedTuple): - expr: TopLevelExpr - info: QAPISourceInfo - doc: Optional['QAPIDoc'] + +# 3.6 workaround: can be removed when Python 3.7+ is our required version. +if TYPE_CHECKING: + _UserDict =3D UserDict[str, object] +else: + _UserDict =3D UserDict + + +class QAPIExpression(_UserDict): + def __init__( + self, + initialdata: Mapping[str, object], + info: QAPISourceInfo, + doc: Optional['QAPIDoc'] =3D None, + ): + super().__init__(initialdata) + self.info =3D info + self.doc: Optional['QAPIDoc'] =3D doc =20 =20 class QAPIParseError(QAPISourceError): @@ -107,7 +118,7 @@ def __init__(self, self.line_pos =3D 0 =20 # Parser output: - self.exprs: List[ParsedExpression] =3D [] + self.exprs: List[QAPIExpression] =3D [] self.docs: List[QAPIDoc] =3D [] =20 # Showtime! @@ -178,10 +189,10 @@ def _parse(self) -> None: cur_doc =3D None self.reject_expr_doc(cur_doc) =20 - def _add_expr(self, expr: TopLevelExpr, + def _add_expr(self, expr: Mapping[str, object], info: QAPISourceInfo, doc: Optional['QAPIDoc'] =3D None) -> None: - self.exprs.append(ParsedExpression(expr, info, doc)) + self.exprs.append(QAPIExpression(expr, info, doc)) =20 @staticmethod def reject_expr_doc(doc: Optional['QAPIDoc']) -> None: @@ -791,7 +802,7 @@ def connect_feature(self, feature: 'QAPISchemaFeature')= -> None: % feature.name) self.features[feature.name].connect(feature) =20 - def check_expr(self, expr: TopLevelExpr) -> None: + def check_expr(self, expr: QAPIExpression) -> None: if self.has_section('Returns') and 'command' not in expr: raise QAPISemError(self.info, "'Returns:' is only valid for commands") diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 89f8e60db36..295c21eab22 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -17,7 +17,7 @@ from collections import OrderedDict import os import re -from typing import Optional +from typing import List, Optional =20 from .common import ( POINTER_SUFFIX, @@ -29,7 +29,7 @@ ) from .error import QAPIError, QAPISemError, QAPISourceError from .expr import check_exprs -from .parser import QAPISchemaParser +from .parser import QAPIExpression, QAPISchemaParser =20 =20 class QAPISchemaIfCond: @@ -964,10 +964,11 @@ def module_by_fname(self, fname): name =3D self._module_name(fname) return self._module_dict[name] =20 - def _def_include(self, expr, info, doc): + def _def_include(self, expr: QAPIExpression): include =3D expr['include'] - assert doc is None - self._def_entity(QAPISchemaInclude(self._make_module(include), inf= o)) + assert expr.doc is None + self._def_entity( + QAPISchemaInclude(self._make_module(include), expr.info)) =20 def _def_builtin_type(self, name, json_type, c_type): self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type)) @@ -1045,15 +1046,15 @@ def _make_implicit_object_type(self, name, info, if= cond, role, members): name, info, None, ifcond, None, None, members, None)) return name =20 - def _def_enum_type(self, expr, info, doc): + def _def_enum_type(self, expr: QAPIExpression): name =3D expr['enum'] data =3D expr['data'] prefix =3D expr.get('prefix') ifcond =3D QAPISchemaIfCond(expr.get('if')) - features =3D self._make_features(expr.get('features'), info) + features =3D self._make_features(expr.get('features'), expr.info) self._def_entity(QAPISchemaEnumType( - name, info, doc, ifcond, features, - self._make_enum_members(data, info), prefix)) + name, expr.info, expr.doc, ifcond, features, + self._make_enum_members(data, expr.info), prefix)) =20 def _make_member(self, name, typ, ifcond, features, info): optional =3D False @@ -1072,15 +1073,15 @@ def _make_members(self, data, info): value.get('features'), info) for (key, value) in data.items()] =20 - def _def_struct_type(self, expr, info, doc): + def _def_struct_type(self, expr: QAPIExpression): name =3D expr['struct'] base =3D expr.get('base') data =3D expr['data'] ifcond =3D QAPISchemaIfCond(expr.get('if')) - features =3D self._make_features(expr.get('features'), info) + features =3D self._make_features(expr.get('features'), expr.info) self._def_entity(QAPISchemaObjectType( - name, info, doc, ifcond, features, base, - self._make_members(data, info), + name, expr.info, expr.doc, ifcond, features, base, + self._make_members(data, expr.info), None)) =20 def _make_variant(self, case, typ, ifcond, info): @@ -1089,46 +1090,49 @@ def _make_variant(self, case, typ, ifcond, info): typ =3D self._make_array_type(typ[0], info) return QAPISchemaVariant(case, info, typ, ifcond) =20 - def _def_union_type(self, expr, info, doc): + def _def_union_type(self, expr: QAPIExpression): name =3D expr['union'] base =3D expr['base'] tag_name =3D expr['discriminator'] data =3D expr['data'] + assert isinstance(data, dict) ifcond =3D QAPISchemaIfCond(expr.get('if')) - features =3D self._make_features(expr.get('features'), info) + features =3D self._make_features(expr.get('features'), expr.info) if isinstance(base, dict): base =3D self._make_implicit_object_type( - name, info, ifcond, - 'base', self._make_members(base, info)) + name, expr.info, ifcond, + 'base', self._make_members(base, expr.info)) variants =3D [ self._make_variant(key, value['type'], QAPISchemaIfCond(value.get('if')), - info) + expr.info) for (key, value) in data.items()] - members =3D [] + members: List[QAPISchemaObjectTypeMember] =3D [] self._def_entity( - QAPISchemaObjectType(name, info, doc, ifcond, features, + QAPISchemaObjectType(name, expr.info, expr.doc, ifcond, featur= es, base, members, QAPISchemaVariants( - tag_name, info, None, variants))) + tag_name, expr.info, None, variants))) =20 - def _def_alternate_type(self, expr, info, doc): + def _def_alternate_type(self, expr: QAPIExpression): name =3D expr['alternate'] data =3D expr['data'] + assert isinstance(data, dict) ifcond =3D QAPISchemaIfCond(expr.get('if')) - features =3D self._make_features(expr.get('features'), info) + features =3D self._make_features(expr.get('features'), expr.info) variants =3D [ self._make_variant(key, value['type'], QAPISchemaIfCond(value.get('if')), - info) + expr.info) for (key, value) in data.items()] - tag_member =3D QAPISchemaObjectTypeMember('type', info, 'QType', F= alse) + tag_member =3D QAPISchemaObjectTypeMember( + 'type', expr.info, 'QType', False) self._def_entity( - QAPISchemaAlternateType(name, info, doc, ifcond, features, - QAPISchemaVariants( - None, info, tag_member, variants))) + QAPISchemaAlternateType( + name, expr.info, expr.doc, ifcond, features, + QAPISchemaVariants(None, expr.info, tag_member, variants))) =20 - def _def_command(self, expr, info, doc): + def _def_command(self, expr: QAPIExpression): name =3D expr['command'] data =3D expr.get('data') rets =3D expr.get('returns') @@ -1139,52 +1143,49 @@ def _def_command(self, expr, info, doc): allow_preconfig =3D expr.get('allow-preconfig', False) coroutine =3D expr.get('coroutine', False) ifcond =3D QAPISchemaIfCond(expr.get('if')) - features =3D self._make_features(expr.get('features'), info) + features =3D self._make_features(expr.get('features'), expr.info) if isinstance(data, OrderedDict): data =3D self._make_implicit_object_type( - name, info, ifcond, - 'arg', self._make_members(data, info)) + name, expr.info, ifcond, + 'arg', self._make_members(data, expr.info)) if isinstance(rets, list): assert len(rets) =3D=3D 1 - rets =3D self._make_array_type(rets[0], info) - self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, featur= es, - data, rets, + rets =3D self._make_array_type(rets[0], expr.info) + self._def_entity(QAPISchemaCommand(name, expr.info, expr.doc, ifco= nd, + features, data, rets, gen, success_response, boxed, allow_oob, allow_preconf= ig, coroutine)) =20 - def _def_event(self, expr, info, doc): + def _def_event(self, expr: QAPIExpression): name =3D expr['event'] data =3D expr.get('data') boxed =3D expr.get('boxed', False) ifcond =3D QAPISchemaIfCond(expr.get('if')) - features =3D self._make_features(expr.get('features'), info) + features =3D self._make_features(expr.get('features'), expr.info) if isinstance(data, OrderedDict): data =3D self._make_implicit_object_type( - name, info, ifcond, - 'arg', self._make_members(data, info)) - self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features, - data, boxed)) + name, expr.info, ifcond, + 'arg', self._make_members(data, expr.info)) + self._def_entity(QAPISchemaEvent(name, expr.info, expr.doc, ifcond, + features, data, boxed)) =20 def _def_exprs(self, exprs): - for expr_elem in exprs: - expr =3D expr_elem.expr - info =3D expr_elem.info - doc =3D expr_elem.doc + for expr in exprs: if 'enum' in expr: - self._def_enum_type(expr, info, doc) + self._def_enum_type(expr) elif 'struct' in expr: - self._def_struct_type(expr, info, doc) + self._def_struct_type(expr) elif 'union' in expr: - self._def_union_type(expr, info, doc) + self._def_union_type(expr) elif 'alternate' in expr: - self._def_alternate_type(expr, info, doc) + self._def_alternate_type(expr) elif 'command' in expr: - self._def_command(expr, info, doc) + self._def_command(expr) elif 'event' in expr: - self._def_event(expr, info, doc) + self._def_event(expr) elif 'include' in expr: - self._def_include(expr, info, doc) + self._def_include(expr) else: assert False =20 --=20 2.39.0 From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822468; cv=none; d=zohomail.com; s=zohoarc; b=Oa2dgqZ1hVUR+Twq98Jmi6EJNPcawEfIy39Rz0cY06iXBx6iyFKHgstP3Wqogk2kZJoI8J1oKMq9LUawYm17eH2jUKHXEXP4IyWbV3jUJTICc0q8y2lVDW7dHExXIjpMjCnuozoFPpEbs5gOiaHHECk66mqKIltVCB7XdL+6zOk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822468; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=8wpKnnp2mX2s8IwhDrHQSvpNtqk7kr+dAB4saNeuHZQ=; b=RKlw/NC4NeGuump7KmLIfd8VDtbJtv9apybZzR8bnuEESGRib7oiyrnz7wTnvBAofJ/Ts0njMfHvi8TIO9XluGovQGmnAGJuv5g/XXn2zfBosiiJfgxV5hJOFcM/a4GOQUCR/EzwTT6fZ+5yvXrxfojtKlcTfhBBPZUlZGOTCXI= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822468794836.7279886062348; Tue, 7 Feb 2023 18:14:28 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxS-0002jG-6u; Tue, 07 Feb 2023 21:13:14 -0500 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 1pPZxQ-0002iP-Jy for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:12 -0500 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 1pPZxO-00040T-2O for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:12 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-628-3rBiH0YwNBaQUH83fu_n3A-1; Tue, 07 Feb 2023 21:13:08 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0A974800B23; Wed, 8 Feb 2023 02:13:08 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id CE8E61121314; Wed, 8 Feb 2023 02:13:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822389; 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=8wpKnnp2mX2s8IwhDrHQSvpNtqk7kr+dAB4saNeuHZQ=; b=HLyd6hNXvTNXa3vJtJgmh5q7+GWAWwGi2NAelZLpPJFKMoVTcA/qYwwVQ0fL4/h81098Ms 4cCgkzZIiFRRe/ULJnUtwTJ6heItGYxa8CNmsAFIfFfmu5SoAv6RhEAzijILMcUTbQwjaA SXFwS/ulo3qc6u8+V3qeDKdUY8x1JWU= X-MC-Unique: 3rBiH0YwNBaQUH83fu_n3A-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 6/7] qapi: remove _JSONObject Date: Tue, 7 Feb 2023 21:13:05 -0500 Message-Id: <20230208021306.870657-7-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822469931100001 Content-Type: text/plain; charset="utf-8" We can remove this alias as it only has two usages now, and no longer pays for the confusion of "yet another type". Signed-off-by: John Snow --- scripts/qapi/expr.py | 13 +++---------- scripts/qapi/parser.py | 5 ++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 83fa7a85b06..0a74feab92f 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -48,14 +48,6 @@ from .source import QAPISourceInfo =20 =20 -# Deserialized JSON objects as returned by the parser. -# The values of this mapping are not necessary to exhaustively type -# here (and also not practical as long as mypy lacks recursive -# types), because the purpose of this module is to interrogate that -# type. -_JSONObject =3D Mapping[str, object] - - # See check_name_str(), below. valid_name =3D re.compile(r'(__[a-z0-9.-]+_)?' r'(x-)?' @@ -192,7 +184,7 @@ def check_defn_name_str(name: str, info: QAPISourceInfo= , meta: str) -> None: info, "%s name should not end in 'List'" % meta) =20 =20 -def check_keys(value: _JSONObject, +def check_keys(value: Mapping[str, object], info: QAPISourceInfo, source: str, required: Collection[str], @@ -256,7 +248,8 @@ def check_flags(expr: QAPIExpression) -> None: expr.info, "flags 'allow-oob' and 'coroutine' are incompatible= ") =20 =20 -def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None: +def check_if(expr: Mapping[str, object], + info: QAPISourceInfo, source: str) -> None: """ Validate the ``if`` member of an object. =20 diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 88f6fdfa67b..315660e8671 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -42,9 +42,8 @@ _ExprValue =3D Union[List[object], Dict[str, object], str, bool] =20 =20 -# FIXME: Consolidate and centralize definitions for _ExprValue, -# JSONValue, and _JSONObject; currently scattered across several -# modules. +# FIXME: Consolidate and centralize definitions for _ExprValue and +# JSONValue; currently scattered across several modules. =20 =20 # 3.6 workaround: can be removed when Python 3.7+ is our required version. --=20 2.39.0 From nobody Sun Feb 8 20:32:19 2026 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=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1675822433; cv=none; d=zohomail.com; s=zohoarc; b=KLNji+N9BPLHm5XAyLGz5hC1RRazXOjty6KydrYtH9sSeeUraO68OvQ7cJLzy9uwGKD5NdHFMEjYvemMf0C11nZIXOQbpy9QXtOLMpgD2ap5rZO9C3ilwiQrQbGPZvHY9z8OEHQB3uEoM7tlGthgObwYiIe1AuNd0WfA0pakdiM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1675822433; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=8zg1iv+8H84JUzE8gOFuJBHk5PZe5IabjqdnKiheT6E=; b=OVnZgvYSVXCt83T4Ujb+DYHOh8Wt9ef49OVaX99RHETFdvwxAcmYtFzifkaHpJ7/5ROFF3kHTYIiJDZcMq1aJvtMufcuCOO2FsKWZ6TJ4AA37X7wLoECicxMSLvrcyKWBuzr5b3HFFVnqBDB1Hof7EH/CKu0AyqpgMrd5kZOGxQ= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1675822433114592.6434502985611; Tue, 7 Feb 2023 18:13:53 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pPZxU-0002jt-7c; Tue, 07 Feb 2023 21:13:16 -0500 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 1pPZxS-0002jD-3j for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:14 -0500 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 1pPZxQ-00041D-IW for qemu-devel@nongnu.org; Tue, 07 Feb 2023 21:13:13 -0500 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-247-UEp1KAWsN0266dezBUrLUw-1; Tue, 07 Feb 2023 21:13:08 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 46FDF1869B60; Wed, 8 Feb 2023 02:13:08 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.119]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1878B1121314; Wed, 8 Feb 2023 02:13:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675822391; 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=8zg1iv+8H84JUzE8gOFuJBHk5PZe5IabjqdnKiheT6E=; b=fxhNEsXclP5LaQrbEQxajKW+Za/+X1olwucPkyW2Tsxl0inPKI1oXsMYL1AOJ8tcSDU+qV PS8ZHJSvkht+NiL/xAsMmhm9Us3VVpiESZHPQf6GiAuvb3KMG8lAgvPIm3uNHjiLX3c0Ae qBl1d5sM3rEDXQCP/b2DkMOwe+kh+Cs= X-MC-Unique: UEp1KAWsN0266dezBUrLUw-1 From: John Snow To: qemu-devel@nongnu.org Cc: Michael Roth , Markus Armbruster , John Snow Subject: [PATCH v2 7/7] qapi: remove JSON value FIXME Date: Tue, 7 Feb 2023 21:13:06 -0500 Message-Id: <20230208021306.870657-8-jsnow@redhat.com> In-Reply-To: <20230208021306.870657-1-jsnow@redhat.com> References: <20230208021306.870657-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 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: -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, 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_H2=-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: 1675822433889100005 Content-Type: text/plain; charset="utf-8" With the two major JSON-ish type hierarchies clarified for distinct purposes; QAPIExpression for parsed expressions and JSONValue for introspection data, remove this FIXME as no longer an action item. In theory, it may be possible to define a completely agnostic one-size-fits-all JSON type hierarchy that any other user could borrow - in practice, it's tough to wrangle the differences between invariant, covariant and contravariant types: input and output parameters demand different properties of such a structure. As such, it's simply more trouble than it's worth. So, declare this "done enough for now". Signed-off-by: John Snow --- scripts/qapi/parser.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 315660e8671..556092f37b1 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -42,10 +42,6 @@ _ExprValue =3D Union[List[object], Dict[str, object], str, bool] =20 =20 -# FIXME: Consolidate and centralize definitions for _ExprValue and -# JSONValue; currently scattered across several modules. - - # 3.6 workaround: can be removed when Python 3.7+ is our required version. if TYPE_CHECKING: _UserDict =3D UserDict[str, object] --=20 2.39.0