From nobody Thu Apr 2 07:43:45 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1774866531; cv=none; d=zohomail.com; s=zohoarc; b=d+3T6E1WkfRpqpxXv8mxAiqwtPVHsIr/eygIP6KW+YvQRfqgrMhI6l6hLIlPxDyCFxhqZa/6Sor5tbq0FoJKaHtgJAhdWocGuRYLhTzFQYZDfhQdGSC6oqqWgRptfWOZvpezhJ0JnFJIVck4bitFgCikvSKjHHC5oCwasANkjSw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1774866531; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ZzLI3i6RBHWPskf4fOd5vHu0dONnrjAKnFaoAf5UPjI=; b=RTlGiDVJzTSH7WE1lLNePUemD8VV52kcrKvFnhDctdgL2WWjfpfBXxhtYlfLBb4twUKB26HzgQE7R4ZpbciYveAcF61r/a88qI3EyE5kTQqZ8HWmpikxOiiAV1O8ikAD7A+AuIXzpX5RL/7DAYxMTmtYSxiKEBUSjyP0cef9Whg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1774866531198915.0943695124671; Mon, 30 Mar 2026 03:28:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w79rM-00016E-9v; Mon, 30 Mar 2026 06:28:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w79rA-000143-J3 for qemu-devel@nongnu.org; Mon, 30 Mar 2026 06:28:29 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w79r8-0005DH-FP for qemu-devel@nongnu.org; Mon, 30 Mar 2026 06:28:28 -0400 Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-590-6bZCYok2Mwib60jHzdHliQ-1; Mon, 30 Mar 2026 06:28:22 -0400 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 224991800283; Mon, 30 Mar 2026 10:28:21 +0000 (UTC) Received: from thuth-p1g4.redhat.com (unknown [10.44.35.14]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D8B4830001A1; Mon, 30 Mar 2026 10:28:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774866505; 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=ZzLI3i6RBHWPskf4fOd5vHu0dONnrjAKnFaoAf5UPjI=; b=c2HkHd9iJ2SOMQFW+hZlQONIb0cUTgfU6466G3v1vl4ytxhscfh4ig506CinVK5MHH3EGP 9jP8GlsHBPVYP6bIebP3kkmta6ht8NEVB8ZD8M8HSlkCIIotVDar4zL+kTcc1ldtavjZrT fx4D16HPUBUALGM0AKMqpSrG7g14Fd4= X-MC-Unique: 6bZCYok2Mwib60jHzdHliQ-1 X-Mimecast-MFC-AGG-ID: 6bZCYok2Mwib60jHzdHliQ_1774866501 From: Thomas Huth To: Peter Maydell Cc: qemu-devel@nongnu.org Subject: [PULL 1/7] tests/functional/qemu_test: Silence (most) warnings from pylint in asset.py Date: Mon, 30 Mar 2026 12:28:09 +0200 Message-ID: <20260330102815.6759-2-thuth@redhat.com> In-Reply-To: <20260330102815.6759-1-thuth@redhat.com> References: <20260330102815.6759-1-thuth@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 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=thuth@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -6 X-Spam_score: -0.7 X-Spam_bar: / X-Spam_report: (-0.7 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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.01, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=1, RCVD_IN_VALIDITY_RPBL_BLOCKED=1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development 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: 1774866532989154100 Content-Type: text/plain; charset="utf-8" From: Thomas Huth Pylint currently complains: asset.py:1:0: C0114: Missing module docstring (missing-module-docstring) asset.py:21:0: C0115: Missing class docstring (missing-class-docstring) asset.py:28:15: C0209: Formatting a regular string which could be an f-str= ing (consider-using-f-string) asset.py:34:0: C0115: Missing class docstring (missing-class-docstring) asset.py:49:15: C0209: Formatting a regular string which could be an f-str= ing (consider-using-f-string) asset.py:73:4: C0116: Missing function or method docstring (missing-functi= on-docstring) asset.py:80:4: C0116: Missing function or method docstring (missing-functi= on-docstring) asset.py:83:4: C0116: Missing function or method docstring (missing-functi= on-docstring) asset.py:125:4: C0116: Missing function or method docstring (missing-funct= ion-docstring) asset.py:181:43: C0209: Formatting a regular string which could be an f-st= ring (consider-using-f-string) asset.py:190:39: C0209: Formatting a regular string which could be an f-st= ring (consider-using-f-string) asset.py:201:39: C0209: Formatting a regular string which could be an f-st= ring (consider-using-f-string) asset.py:213:15: W0718: Catching too general exception Exception (broad-ex= ception-caught) asset.py:218:35: C0209: Formatting a regular string which could be an f-st= ring (consider-using-f-string) asset.py:125:4: R0912: Too many branches (16/12) (too-many-branches) asset.py:125:4: R0915: Too many statements (64/50) (too-many-statements) asset.py:228:4: C0116: Missing function or method docstring (missing-funct= ion-docstring) asset.py:249:4: C0116: Missing function or method docstring (missing-funct= ion-docstring) asset.py:257:4: C0116: Missing function or method docstring (missing-funct= ion-docstring) Fix all the warnings except for the R0912 and R0915 which will be tackled in a later commit. And while we're at it, also add a proper SPDX license identifier. Signed-off-by: Thomas Huth Message-ID: <20260324163543.55503-3-thuth@redhat.com> --- tests/functional/qemu_test/asset.py | 53 +++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_te= st/asset.py index 45a2e01e2e6..1cd03c2a9a9 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -1,9 +1,12 @@ -# Test utilities for fetching & caching assets +# SPDX-License-Identifier: GPL-2.0-or-later # # Copyright 2024 Red Hat, Inc. # # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. +''' +Test utilities for fetching & caching assets +''' =20 import hashlib import logging @@ -18,21 +21,27 @@ from shutil import copyfileobj from urllib.error import HTTPError, URLError =20 + class AssetError(Exception): + '''This exception will be raised if an asset is not usable''' def __init__(self, asset, msg, transient=3DFalse): self.url =3D asset.url self.msg =3D msg self.transient =3D transient =20 def __str__(self): - return "%s: %s" % (self.url, self.msg) + return f"{self.url}: {self.msg}" =20 -# Instances of this class must be declared as class level variables -# starting with a name "ASSET_". This enables the pre-caching logic -# to easily find all referenced assets and download them prior to -# execution of the tests. -class Asset: =20 +class Asset: + ''' + This class is used to represent an asset that gets downloaded from + the internet and will be stored in the local asset cache. + Instances of this class must be declared as class level variables + starting with a name "ASSET_". This enables the pre-caching logic + to easily find all referenced assets and download them prior to + execution of the tests. + ''' def __init__(self, url, hashsum): self.url =3D url self.hash =3D hashsum @@ -46,8 +55,7 @@ def __init__(self, url, hashsum): self.log =3D logging.getLogger('qemu-test') =20 def __repr__(self): - return "Asset: url=3D%s hash=3D%s cache=3D%s" % ( - self.url, self.hash, self.cache_file) + return f"Asset: url=3D{self.url} hash=3D{self.hash} cache=3D{self.= cache_file}" =20 def __str__(self): return str(self.cache_file) @@ -71,6 +79,7 @@ def _check(self, cache_file): return self.hash =3D=3D hl.hexdigest() =20 def valid(self): + '''Check whether the file exists in the cache and has the right ha= sh''' if os.getenv("QEMU_TEST_REFRESH_CACHE", None) is not None: self.log.info("Force refresh of asset %s", self.url) return False @@ -78,9 +87,11 @@ def valid(self): return self.cache_file.exists() and self._check(self.cache_file) =20 def fetchable(self): + '''Check whether we are allowed to download assets from the intern= et''' return not os.environ.get("QEMU_TEST_NO_DOWNLOAD", False) =20 def available(self): + '''Check whether the asset is either in the cache or fetchable''' return self.valid() or self.fetchable() =20 def _wait_for_other_download(self, tmp_cache_file): @@ -123,6 +134,7 @@ def _save_time_stamp(self): self.cache_file.with_suffix(".stamp").write_text(f"{int(time.time(= ))}") =20 def fetch(self): + '''Download the asset from the internet''' if not self.cache_dir.exists(): self.cache_dir.mkdir(parents=3DTrue, exist_ok=3DTrue) =20 @@ -179,7 +191,7 @@ def fetch(self): # server or networking problem if e.code =3D=3D 404: raise AssetError(self, "Unable to download: " - "HTTP error %d" % e.code) from e + f"HTTP error {e.code}") from e continue except URLError as e: # This is typically a network/service level error @@ -187,8 +199,9 @@ def fetch(self): tmp_cache_file.unlink() self.log.error("Unable to download %s: URL error %s", self.url, e.reason) - raise AssetError(self, "Unable to download: URL error %s" % - e.reason, transient=3DTrue) from e + raise AssetError(self, + f"Unable to download: URL error{e.reason}= ", + transient=3DTrue) from e except ConnectionError as e: # A socket connection failure, such as dropped conn # or refused conn @@ -198,7 +211,7 @@ def fetch(self): continue except Exception as e: tmp_cache_file.unlink() - raise AssetError(self, "Unable to download: %s" % e, + raise AssetError(self, f"Unable to download: {e}", transient=3DTrue) from e =20 if not os.path.exists(tmp_cache_file): @@ -210,12 +223,12 @@ def fetch(self): self.url.encode('utf8')) os.setxattr(str(tmp_cache_file), "user.qemu-asset-hash", self.hash.encode('utf8')) - except Exception as e: + except OSError as e: self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file= , e) =20 if not self._check(tmp_cache_file): tmp_cache_file.unlink() - raise AssetError(self, "Hash does not match %s" % self.hash) + raise AssetError(self, f"Hash does not match {self.hash}") tmp_cache_file.replace(self.cache_file) self._save_time_stamp() # Remove write perms to stop tests accidentally modifying them @@ -226,6 +239,10 @@ def fetch(self): =20 @staticmethod def precache_test(test): + ''' + Look for variables starting with "ASSET_" and try to fetch the ass= et + that is specified there. + ''' log =3D logging.getLogger('qemu-test') log.setLevel(logging.DEBUG) handler =3D logging.StreamHandler(sys.stdout) @@ -247,6 +264,9 @@ def precache_test(test): =20 @staticmethod def precache_suite(suite): + ''' + Iterate through all tests/suites in a suite and precache their ass= ets + ''' for test in suite: if isinstance(test, unittest.TestSuite): Asset.precache_suite(test) @@ -255,6 +275,9 @@ def precache_suite(suite): =20 @staticmethod def precache_suites(path, cache_tstamp): + ''' + Get the available test suite and precache their assets + ''' loader =3D unittest.loader.defaultTestLoader tests =3D loader.loadTestsFromNames([path], None) =20 --=20 2.53.0