From patchwork Mon Oct 26 21:36:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301934 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 145EAC388F9 for ; Mon, 26 Oct 2020 21:39:13 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B45A92084C for ; Mon, 26 Oct 2020 21:39:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="eiamI49g" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B45A92084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:33726 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXACt-0005nV-Ob for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:39:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60460) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAb-00042L-CI for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:49 -0400 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:20731) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAX-0001Uq-EA for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748202; 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=iNXKETo8JGNIyUIk7CYW1Kx+3IY1lxRFSJg705347q8=; b=eiamI49g2O/F7iAppfVJY6ykcKUzEm1bsGQbpGcGWyhyjHauEyhS9caDm6z8N36Ge55Coi QezxnswvoJyz0Eab34He5J4SjsqMP6n4qYgsBfX5U35QK6GNMgXcOAIAsFRDAvjmvd84OP v8c5S9uxMt1PME2bK1D8CupzYQ3xlfM= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-538-CIcA9dCvMluVpGQXA83Uag-1; Mon, 26 Oct 2020 17:36:41 -0400 X-MC-Unique: CIcA9dCvMluVpGQXA83Uag-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 15EA18064C0 for ; Mon, 26 Oct 2020 21:36:40 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7306919728; Mon, 26 Oct 2020 21:36:39 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 01/16] qapi/expr.py: Remove 'info' argument from nested check_if_str Date: Mon, 26 Oct 2020 17:36:22 -0400 Message-Id: <20201026213637.47087-2-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=63.128.21.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/25 21:03:19 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H5=0.001, RCVD_IN_MSPIKE_WL=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The function can just use the argument from the scope above. Otherwise, we get shadowed argument errors because the parameter name clashes with the name of a variable already in-scope. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 2fcaaa2497a8..35695c4c653b 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -104,7 +104,7 @@ def check_flags(expr, info): def check_if(expr, info, source): - def check_if_str(ifcond, info): + def check_if_str(ifcond): if not isinstance(ifcond, str): raise QAPISemError( info, @@ -124,9 +124,9 @@ def check_if_str(ifcond, info): raise QAPISemError( info, "'if' condition [] of %s is useless" % source) for elt in ifcond: - check_if_str(elt, info) + check_if_str(elt) else: - check_if_str(ifcond, info) + check_if_str(ifcond) expr['if'] = [ifcond] From patchwork Mon Oct 26 21:36:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301931 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D081EC4363A for ; Mon, 26 Oct 2020 21:45:20 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5A00B207DE for ; Mon, 26 Oct 2020 21:45:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="BVOdCwG4" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5A00B207DE Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:53208 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXAIp-0005aj-7D for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:45:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60440) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAa-00041G-9v for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:48 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:27835) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAX-0001V1-Or for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748205; 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=TVAIaUd0qn/L1hYp8sivghgZfYY52GolNO0IpyKQ81g=; b=BVOdCwG4qbAoW2J9DX7HQL0Jx1m7htucNaGcUTIyV3WmFnz4YIcIWVs1x5rqt9tVooCtaa v6BpcUJFEBOIkelCFtZ34TjGh+UhFp4Lid2+Db+4IoadZHaeI964EAVGV2nP9LbpaqBrrV 03DaFCkjdyemzBBz5mlD9TKM1QS+Gsg= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-519-V-tAuQ5TPR2vp6-fHsAByA-1; Mon, 26 Oct 2020 17:36:43 -0400 X-MC-Unique: V-tAuQ5TPR2vp6-fHsAByA-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 770FE8064C0 for ; Mon, 26 Oct 2020 21:36:42 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8047D19728; Mon, 26 Oct 2020 21:36:41 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 03/16] qapi/expr.py: constrain incoming expression types Date: Mon, 26 Oct 2020 17:36:24 -0400 Message-Id: <20201026213637.47087-4-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/26 02:39:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H4=0.001, RCVD_IN_MSPIKE_WL=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" mypy does not know the types of values stored in Dicts that masquerade as objects. Help the type checker out by constraining the type. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 5694c501fa38..f7c7f91326ef 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -15,9 +15,17 @@ # See the COPYING file in the top-level directory. import re +from typing import MutableMapping, Optional from .common import c_name from .error import QAPISemError +from .parser import QAPIDoc +from .source import QAPISourceInfo + + +# Expressions in their raw form are JSON-like structures with arbitrary forms. +# Minimally, their top-level form must be a mapping of strings to values. +Expression = MutableMapping[str, object] # Names must be letters, numbers, -, and _. They must start with letter, @@ -287,9 +295,20 @@ def check_event(expr, info): def check_exprs(exprs): for expr_elem in exprs: - expr = expr_elem['expr'] - info = expr_elem['info'] - doc = expr_elem.get('doc') + # Expression + assert isinstance(expr_elem['expr'], dict) + expr: Expression = expr_elem['expr'] + for key in expr.keys(): + assert isinstance(key, str) + + # QAPISourceInfo + assert isinstance(expr_elem['info'], QAPISourceInfo) + info: QAPISourceInfo = expr_elem['info'] + + # Optional[QAPIDoc] + tmp = expr_elem.get('doc') + assert tmp is None or isinstance(tmp, QAPIDoc) + doc: Optional[QAPIDoc] = tmp if 'include' in expr: continue From patchwork Mon Oct 26 21:36:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301933 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0CD0FC4363A for ; Mon, 26 Oct 2020 21:42:12 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9A50721655 for ; Mon, 26 Oct 2020 21:42:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="VeYXCWsr" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9A50721655 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42042 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXAFm-0000wJ-Mm for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:42:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60448) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAa-00041j-QH for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:48 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:25890) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAZ-0001VB-1O for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748206; 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=S8x50cCMSfplV2qAmTGGgGrsddjWRyaUw3FL/uWzI6o=; b=VeYXCWsrW8CxCNibZhgwgxf5MNiF1xUEpVl7MAv3yrpf8PnD1AdYBjelqEHyUa6D5Oosbt 4myp0x6QUlGUy/qKwfz+ji0w3Afz/lmye5d0MA1K4+eFZqVvnGMSGTblP8fBMVfIGr6Xxg rZMSefBn/qEnnfEPEkkguj7nooC4aU0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-565-R1ooHltuPGKysM7J8hdq1w-1; Mon, 26 Oct 2020 17:36:44 -0400 X-MC-Unique: R1ooHltuPGKysM7J8hdq1w-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4D0E918C89D1 for ; Mon, 26 Oct 2020 21:36:43 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9A5BD19728; Mon, 26 Oct 2020 21:36:42 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 04/16] qapi/expr.py: Add assertion for union type 'check_dict' Date: Mon, 26 Oct 2020 17:36:25 -0400 Message-Id: <20201026213637.47087-5-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/26 02:39:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H4=0.001, RCVD_IN_MSPIKE_WL=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" mypy isn't fond of allowing you to check for bool membership in a collection of str elements. Guard this lookup for precisely when we were given a name. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index f7c7f91326ef..2c4c341d5243 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -173,7 +173,9 @@ def check_type(value, info, source, raise QAPISemError(info, "%s should be an object or type name" % source) - permit_upper = allow_dict in info.pragma.name_case_whitelist + permit_upper = False + if isinstance(allow_dict, str): + permit_upper = allow_dict in info.pragma.name_case_whitelist # value is a dictionary, check that each member is okay for (key, arg) in value.items(): From patchwork Mon Oct 26 21:36:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301932 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43B03C4363A for ; Mon, 26 Oct 2020 21:44:48 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A7C00207DE for ; Mon, 26 Oct 2020 21:44:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="SzFUpD5m" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A7C00207DE Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:50582 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXAII-0004Ui-Mz for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:44:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60522) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAi-00045G-WD for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:57 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:22588) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAc-0001Vl-0l for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:36:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748209; 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=PADkYIFfY8n6yj7AmPITNyc+ufsFjfb5RIBcX2AxO2k=; b=SzFUpD5mv+bv2tW196YfKoTejZLk8hvNrORUMIkE9sDWhfrwSPtXp7rpQ/eGzrkXWUA9nI i/owPtaQWf6MxuyWViixllCj17HLvQ01hpR/NvYbtUzsGi37ey1o4uSeewdpH8O8rmWHLf qes/CqsqB66Og07zvfV5gRBGsYkj9lM= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-11-4AGkohr0OaS7w8fZUBJOxw-1; Mon, 26 Oct 2020 17:36:46 -0400 X-MC-Unique: 4AGkohr0OaS7w8fZUBJOxw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 98F23809DCA for ; Mon, 26 Oct 2020 21:36:45 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0800219728; Mon, 26 Oct 2020 21:36:44 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 07/16] qapi/expr.py: Add casts in a few select cases Date: Mon, 26 Oct 2020 17:36:28 -0400 Message-Id: <20201026213637.47087-8-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/26 02:39:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H4=0.001, RCVD_IN_MSPIKE_WL=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Casts are instructions to the type checker only, they aren't "safe" and should probably be avoided in general. In this case, when we perform type checking on a nested structure, the type of each field does not "stick". We don't need to assert that something is a str if we've already checked that it is -- use a cast instead for these cases. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 2654a72e8333..b8720b723377 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -15,7 +15,7 @@ # See the COPYING file in the top-level directory. import re -from typing import MutableMapping, Optional +from typing import MutableMapping, Optional, cast from .common import c_name from .error import QAPISemError @@ -232,7 +232,7 @@ def check_enum(expr, info): def check_struct(expr, info): - name = expr['struct'] + name = cast(str, expr['struct']) # Asserted in check_exprs members = expr['data'] check_type(members, info, "'data'", allow_dict=name) @@ -240,7 +240,7 @@ def check_struct(expr, info): def check_union(expr, info): - name = expr['union'] + name = cast(str, expr['union']) # Asserted in check_exprs base = expr.get('base') discriminator = expr.get('discriminator') members = expr['data'] @@ -337,7 +337,7 @@ def check_exprs(exprs): else: raise QAPISemError(info, "expression is missing metatype") - name = expr[meta] + name = cast(str, expr[meta]) # asserted right below: check_name_is_str(name, info, "'%s'" % meta) info.set_defn(meta, name) check_defn_name_str(name, info, meta) From patchwork Mon Oct 26 21:36:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301929 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 54559C4363A for ; Mon, 26 Oct 2020 21:52:12 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9939921655 for ; Mon, 26 Oct 2020 21:52:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="G34NvJCL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9939921655 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41566 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXAPS-0004Im-PL for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:52:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60644) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAu-0004Bf-VK for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:37:08 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:51917) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAi-0001WJ-O3 for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:37:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748212; 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=pJIGUTUx3HszdODAMxMubRf0iN87atBmxtqfAT/Ws6A=; b=G34NvJCLs6yR5qwzVJpKOzAw+5K2PLWaoearnveh7xafgB4BjRMDxKNetdAhajq5MT5UHI BNely764TRizXM0dUwzTZt7SxGCZbvdtykaQymfgpRQ23z5fdd4tq6lSMQFAWbB8UZsc63 nz4isauWmw5bFQF0suEYiNZq5P0lwMk= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-329-QMWwBojwPA2T-i4Npah5RQ-1; Mon, 26 Oct 2020 17:36:50 -0400 X-MC-Unique: QMWwBojwPA2T-i4Npah5RQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id A76F6101EBE3 for ; Mon, 26 Oct 2020 21:36:49 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0FDC919728; Mon, 26 Oct 2020 21:36:48 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 12/16] qapi/expr.py: Add docstrings Date: Mon, 26 Oct 2020 17:36:33 -0400 Message-Id: <20201026213637.47087-13-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/26 02:39:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_FILL_THIS_FORM_SHORT=0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: John Snow Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 167 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 99c5c2ff99b0..8ad82ca98864 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- # -# Check (context-free) QAPI schema expression structure -# # Copyright IBM, Corp. 2011 # Copyright (c) 2013-2019 Red Hat Inc. # @@ -14,6 +12,25 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. +""" +Normalize and validate (context-free) QAPI schema expression structures. + +After QAPI expressions are parsed from disk, they are stored in +recursively nested Python data structures using Dict, List, str, bool, +and int. This module ensures that those nested structures have the +correct type(s) and key(s) where appropriate for the QAPI context-free +grammar. + +The QAPI schema expression language allows for syntactic sugar; this +module also handles the normalization process of these nested +structures. + +See `check_exprs` for the main entry point. + +See `schema.QAPISchema` for processing into native Python data +structures and contextual semantic validation. +""" + import re from typing import ( Iterable, @@ -32,7 +49,7 @@ # Arbitrary form for a JSON-like object. _JSObject = MutableMapping[str, object] -# Expressions in their raw form are (just) JSON-like objects. +#: Expressions in their unvalidated form are JSON-like objects. Expression = _JSObject @@ -46,6 +63,7 @@ def check_name_is_str(name: object, info: QAPISourceInfo, source: str) -> None: + """Ensures that ``name`` is a string. [Const]""" if not isinstance(name, str): raise QAPISemError(info, "%s requires a string name" % source) @@ -56,6 +74,25 @@ def check_name_str(name: str, allow_optional: bool = False, enum_member: bool = False, permit_upper: bool = False) -> None: + """ + Ensures a string is a legal name. [Const] + + A name is legal in the default case when: + + - It matches ``(__[a-z0-9.-]+_)?[a-z][a-z0-9_-]*`` + - It does not start with ``q_`` or ``q-`` + + :param name: Name to check. + :param info: QAPI source file information. + :param source: Human-readable str describing "what" this name is. + :param allow_optional: Allow the very first character to be ``*``. + (Cannot be used with ``enum_member``) + :param enum_member: Allow the very first character to be a digit. + (Cannot be used with ``allow_optional``) + :param permit_upper: Allows upper-case characters wherever + lower-case characters are allowed. + """ + assert not (allow_optional and enum_member) membername = name if allow_optional and name.startswith('*'): @@ -76,6 +113,17 @@ def check_name_str(name: str, def check_defn_name_str(name: str, info: QAPISourceInfo, meta: str) -> None: + """ + Ensures a name is a legal definition name. [Const] + + A legal definition name: + - Adheres to the criteria in `check_name_str`, with uppercase permitted + - Does not end with ``Kind`` or ``List``. + + :param name: Name to check. + :param info: QAPI source file information. + :param meta: Type name of the QAPI expression. + """ check_name_str(name, info, meta, permit_upper=True) if name.endswith('Kind') or name.endswith('List'): raise QAPISemError( @@ -87,6 +135,15 @@ def check_keys(value: _JSObject, source: str, required: List[str], optional: List[str]) -> None: + """ + Ensures an object has a specific set of keys. [Const] + + :param value: The object to check. + :param info: QAPI source file information. + :param source: Human-readable str describing "what" this object is. + :param required: Keys that *must* be present. + :param optional: Keys that *may* be present. + """ def pprint(elems: Iterable[str]) -> str: return ', '.join("'" + e + "'" for e in sorted(elems)) @@ -109,6 +166,12 @@ def pprint(elems: Iterable[str]) -> str: def check_flags(expr: Expression, info: QAPISourceInfo) -> None: + """ + Ensures common fields in an Expression are correct. [Const] + + :param expr: Expression to validate. + :param info: QAPI source file information. + """ for key in ['gen', 'success-response']: if key in expr and expr[key] is not False: raise QAPISemError( @@ -127,6 +190,19 @@ def check_flags(expr: Expression, info: QAPISourceInfo) -> None: def check_if(expr: _JSObject, info: QAPISourceInfo, source: str) -> None: + """ + Syntactically validate and normalize the ``if`` field of an object. [RW] + + The ``if`` field may be either a ``str`` or a ``List[str]``. + A ``str`` element will be normalized to ``List[str]``. + + :param expr: A ``dict``; the ``if`` field, if present, will be validated. + :param info: QAPI source file information. + + :forms: + :sugared: ``Union[str, List[str]]`` + :canonical: ``List[str]`` + """ def check_if_str(ifcond: object) -> None: if not isinstance(ifcond, str): @@ -155,6 +231,17 @@ def check_if_str(ifcond: object) -> None: def normalize_members(members: object) -> None: + """ + Normalize a "members" value. [RW] + + If ``members`` is an object, for every value in that object, if that + value is not itself already an object, normalize it to + ``{'type': value}``. + + :forms: + :sugared: ``Dict[str, Union[str, TypeRef]]`` + :canonical: ``Dict[str, TypeRef]`` + """ if isinstance(members, dict): for key, arg in members.items(): if isinstance(arg, dict): @@ -167,6 +254,21 @@ def check_type(value: Optional[object], source: str, allow_array: bool = False, allow_dict: Union[bool, str] = False) -> None: + """ + Check the QAPI type of ``value``. [RW] + + Python types of ``str`` or ``None`` are always allowed. + + :param value: The value to check. + :param info: QAPI Source file information. + :param source: Human readable string describing "what" the value is. + :param allow_array: Allow a ``List[str]`` of length 1, + which indicates an Array type. + :param allow_dict: Allow a dict, treated as an anonymous type. + When given a string, check if that name is allowed to + have keys that use uppercase letters, and modify + validation accordingly. + """ if value is None: return @@ -212,6 +314,16 @@ def check_type(value: Optional[object], def check_features(features: Optional[object], info: QAPISourceInfo) -> None: + """ + Syntactically validate and normalize the ``features`` field. [RW] + + ``features`` may be a ``list`` of either ``str`` or ``dict``. + Any ``str`` element will be normalized to ``{'name': element}``. + + :forms: + :sugared: ``List[Union[str, Feature]]`` + :canonical: ``List[Feature]`` + """ if features is None: return if not isinstance(features, list): @@ -229,6 +341,12 @@ def check_features(features: Optional[object], def check_enum(expr: Expression, info: QAPISourceInfo) -> None: + """ + Validate this `Expression` as an ``enum`` expression. [RW] + + :param expr: `Expression` to validate. + :param info: QAPI source file information. + """ name = expr['enum'] members = expr['data'] prefix = expr.get('prefix') @@ -253,6 +371,12 @@ def check_enum(expr: Expression, info: QAPISourceInfo) -> None: def check_struct(expr: Expression, info: QAPISourceInfo) -> None: + """ + Validate this `Expression` as a ``struct`` expression. [RW] + + :param expr: `Expression` to validate. + :param info: QAPI source file information. + """ name = cast(str, expr['struct']) # Asserted in check_exprs members = expr['data'] @@ -261,6 +385,12 @@ def check_struct(expr: Expression, info: QAPISourceInfo) -> None: def check_union(expr: Expression, info: QAPISourceInfo) -> None: + """ + Validate this `Expression` as a ``union`` expression. [RW] + + :param expr: `Expression` to validate. + :param info: QAPI source file information. + """ name = cast(str, expr['union']) # Asserted in check_exprs base = expr.get('base') discriminator = expr.get('discriminator') @@ -287,6 +417,12 @@ def check_union(expr: Expression, info: QAPISourceInfo) -> None: def check_alternate(expr: Expression, info: QAPISourceInfo) -> None: + """ + Validate this `Expression` as an ``alternate`` expression. [RW] + + :param expr: Expression to validate. + :param info: QAPI source file information. + """ members = expr['data'] if not members: @@ -304,6 +440,12 @@ def check_alternate(expr: Expression, info: QAPISourceInfo) -> None: def check_command(expr: Expression, info: QAPISourceInfo) -> None: + """ + Validate this `Expression` as a ``command`` expression. [RW] + + :param expr: `Expression` to validate. + :param info: QAPI source file information. + """ args = expr.get('data') rets = expr.get('returns') boxed = expr.get('boxed', False) @@ -315,6 +457,16 @@ def check_command(expr: Expression, info: QAPISourceInfo) -> None: def check_event(expr: Expression, info: QAPISourceInfo) -> None: + """ + Normalize and syntactically validate the ``event`` expression. [RW] + + :Event: + :event: ``str`` + :data: ``Optional[Dict[str, Member]]`` + :boxed: ``Optional[bool]`` + :if: ``Optional[Ifcond]`` (see: `check_if`) + :features: ``Optional[Features]`` (see: `check_features`) + """ args = expr.get('data') boxed = expr.get('boxed', False) @@ -324,6 +476,15 @@ def check_event(expr: Expression, info: QAPISourceInfo) -> None: def check_exprs(exprs: List[_JSObject]) -> List[_JSObject]: + """ + Validate and normalize a list of parsed QAPI schema expressions. [RW] + + This function accepts a list of expressions + metadta as returned by + the parser. It destructively normalizes the expressions in-place. + + :param exprs: The list of expressions to normalize/validate. + :return: The same list of expressions (now modified). + """ for expr_elem in exprs: # Expression assert isinstance(expr_elem['expr'], dict) From patchwork Mon Oct 26 21:36:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301928 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7FBE1C4363A for ; Mon, 26 Oct 2020 21:55:17 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D00AF2084C for ; Mon, 26 Oct 2020 21:55:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="NhJbSqpx" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D00AF2084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:45816 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXASR-0006B8-RM for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:55:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60682) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAv-0004Ea-V9 for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:37:09 -0400 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:48324) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAi-0001WO-O0 for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:37:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748213; 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=gGFAJIbWrsePAIhsW7EqR0u/1Qreg8w5S8GElOz37dI=; b=NhJbSqpxIp9u7GOchtLLR6EGg0DbnztI6kROPUMsd/GNAh3VXJG5HvXK8qEZY0oDAPc+Kw f3M2vSm3+iSVH89WKVXTQOkwwOnqtjukMCUPfXHz6abMITc905rRDgS2QUZBWjRP2j9z5w B/AdMoKwU/VrPcnHjpJ+ZM9M2bCqB0c= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-400-c67zQgCKOACKkR5HuOn70A-1; Mon, 26 Oct 2020 17:36:51 -0400 X-MC-Unique: c67zQgCKOACKkR5HuOn70A-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6BE4E8030B2 for ; Mon, 26 Oct 2020 21:36:50 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id C956E19D6C; Mon, 26 Oct 2020 21:36:49 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 13/16] qapi/expr.py: Modify check_keys to accept any Iterable Date: Mon, 26 Oct 2020 17:36:34 -0400 Message-Id: <20201026213637.47087-14-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=63.128.21.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/25 21:03:19 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H5=0.001, RCVD_IN_MSPIKE_WL=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This is a very minor adjustment. a + b is list-specific behavior, but we can accept a wider variety of types in a more pythonic fashion if we avoid that behavior. Typing it this way allows callers to use things like dict.keys() and other iterables that are not their own discrete lists. Including it just as a statement of practice if nothing else: It's nice to use the least-specific type possible as function input and use the most-specific type for returns. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 8ad82ca98864..883aa1781599 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -133,8 +133,8 @@ def check_defn_name_str(name: str, info: QAPISourceInfo, meta: str) -> None: def check_keys(value: _JSObject, info: QAPISourceInfo, source: str, - required: List[str], - optional: List[str]) -> None: + required: Iterable[str] = (), + optional: Iterable[str] = ()) -> None: """ Ensures an object has a specific set of keys. [Const] @@ -155,7 +155,7 @@ def pprint(elems: Iterable[str]) -> str: "%s misses key%s %s" % (source, 's' if len(missing) > 1 else '', pprint(missing))) - allowed = set(required + optional) + allowed = set(required) | set(optional) unknown = set(value) - allowed if unknown: raise QAPISemError( From patchwork Mon Oct 26 21:36:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 301930 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45561C4363A for ; Mon, 26 Oct 2020 21:50:12 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A5308207F7 for ; Mon, 26 Oct 2020 21:50:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ai7vVRuY" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A5308207F7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:37276 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kXANW-0002OP-Mp for qemu-devel@archiver.kernel.org; Mon, 26 Oct 2020 17:50:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60610) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXAAo-00049P-3M for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:37:02 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:22833) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kXAAi-0001WY-MX for qemu-devel@nongnu.org; Mon, 26 Oct 2020 17:37:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1603748214; 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=BzR1jpkyEvGckWPaDmHWHkzzpNd44v+7R6OfTtEDH+4=; b=ai7vVRuYeWb67kw6uWumS827eIlfWTPuXo5olEEVmI0lFXPcLdg/5A7okIyVryIMRNfqSp Wxum5cFjkn90HhgXYTY3s9xvT7hGVK/byxDdEjMWOmaCYVOfFqBwNbaJQEaziFMkp9VtIs ZcG/E3dfJbZwDb8js0OUHWkFekyvlfk= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-155-Tbxvh5SfNJ24Eyvs5WQ9zw-1; Mon, 26 Oct 2020 17:36:52 -0400 X-MC-Unique: Tbxvh5SfNJ24Eyvs5WQ9zw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id F3745809DD5 for ; Mon, 26 Oct 2020 21:36:51 +0000 (UTC) Received: from scv.redhat.com (ovpn-118-238.rdu2.redhat.com [10.10.118.238]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5B90519728; Mon, 26 Oct 2020 21:36:51 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org, Markus Armbruster Subject: [PATCH v2 15/16] qapi/expr.py: move related checks inside check_xxx functions Date: Mon, 26 Oct 2020 17:36:36 -0400 Message-Id: <20201026213637.47087-16-jsnow@redhat.com> In-Reply-To: <20201026213637.47087-1-jsnow@redhat.com> References: <20201026213637.47087-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/26 02:39:09 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_FILL_THIS_FORM_SHORT=0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Eduardo Habkost , Cleber Rosa Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" There's not a big obvious difference between the types of checks that happen in the main function versus the kind that happen in the functions. Now they're in one place for each of the main types. As part of the move, spell out the required and optional keywords so they're obvious at a glance. Signed-off-by: John Snow Reviewed-by: Cleber Rosa --- scripts/qapi/expr.py | 55 ++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 9253560cd9ce..3b62e801a42c 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -347,6 +347,10 @@ def check_enum(expr: Expression, info: QAPISourceInfo) -> None: :param expr: `Expression` to validate. :param info: QAPI source file information. """ + check_keys(expr, info, 'enum', + required=('enum', 'data'), + optional=('if', 'features', 'prefix')) + name = expr['enum'] members = expr['data'] prefix = expr.get('prefix') @@ -377,6 +381,11 @@ def check_struct(expr: Expression, info: QAPISourceInfo) -> None: :param expr: `Expression` to validate. :param info: QAPI source file information. """ + check_keys(expr, info, 'struct', + required=('struct', 'data'), + optional=('base', 'if', 'features')) + normalize_members(expr['data']) + name = cast(str, expr['struct']) # Asserted in check_exprs members = expr['data'] @@ -391,6 +400,13 @@ def check_union(expr: Expression, info: QAPISourceInfo) -> None: :param expr: `Expression` to validate. :param info: QAPI source file information. """ + check_keys(expr, info, 'union', + required=('union', 'data'), + optional=('base', 'discriminator', 'if', 'features')) + + normalize_members(expr.get('base')) + normalize_members(expr['data']) + name = cast(str, expr['union']) # Asserted in check_exprs base = expr.get('base') discriminator = expr.get('discriminator') @@ -423,6 +439,11 @@ def check_alternate(expr: Expression, info: QAPISourceInfo) -> None: :param expr: Expression to validate. :param info: QAPI source file information. """ + check_keys(expr, info, 'alternate', + required=('alternate', 'data'), + optional=('if', 'features')) + normalize_members(expr['data']) + members = expr['data'] if not members: @@ -446,6 +467,13 @@ def check_command(expr: Expression, info: QAPISourceInfo) -> None: :param expr: `Expression` to validate. :param info: QAPI source file information. """ + check_keys(expr, info, 'command', + required=['command'], + optional=('data', 'returns', 'boxed', 'if', 'features', + 'gen', 'success-response', 'allow-oob', + 'allow-preconfig', 'coroutine')) + normalize_members(expr.get('data')) + args = expr.get('data') rets = expr.get('returns') boxed = expr.get('boxed', False) @@ -467,6 +495,11 @@ def check_event(expr: Expression, info: QAPISourceInfo) -> None: :if: ``Optional[Ifcond]`` (see: `check_if`) :features: ``Optional[Features]`` (see: `check_features`) """ + check_keys(expr, info, 'event', + required=['event'], + optional=('data', 'boxed', 'if', 'features')) + normalize_members(expr.get('data')) + args = expr.get('data') boxed = expr.get('boxed', False) @@ -534,38 +567,16 @@ def check_exprs(exprs: List[_JSObject]) -> List[_JSObject]: "documentation comment required") if meta == 'enum': - check_keys(expr, info, meta, - ['enum', 'data'], ['if', 'features', 'prefix']) check_enum(expr, info) elif meta == 'union': - check_keys(expr, info, meta, - ['union', 'data'], - ['base', 'discriminator', 'if', 'features']) - normalize_members(expr.get('base')) - normalize_members(expr['data']) check_union(expr, info) elif meta == 'alternate': - check_keys(expr, info, meta, - ['alternate', 'data'], ['if', 'features']) - normalize_members(expr['data']) check_alternate(expr, info) elif meta == 'struct': - check_keys(expr, info, meta, - ['struct', 'data'], ['base', 'if', 'features']) - normalize_members(expr['data']) check_struct(expr, info) elif meta == '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 == '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'