From patchwork Fri May 1 11:00:20 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2271 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1777633340; bh=jq3pixFgNP/KtSlwjlLi8y3bbcHe+6xVAHIaD328jO8=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=oPibbILjdIazAnFkpdbnbA2oIebcFy4+COHSqTh1w1rtGkYbb721b1FLhPjjwwlmE K+6cHI6N+kZlpFowxDRrzFqhlonS49GR0atpZzDDelyd7SL9Eyktf07spqvizqiWa7 NWqWdotSbotnu+f6qZ3dyyQf1RyQib+P+WbBViK4= Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 709676A857 for ; Fri, 1 May 2026 05:02:20 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id kwnfS7s1YFQ8 for ; Fri, 1 May 2026 05:02:20 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1777633338; bh=jq3pixFgNP/KtSlwjlLi8y3bbcHe+6xVAHIaD328jO8=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=O4NGtBc28c6yXPTan1gwSTqmRGKW2B16q797giBcmu518pXpOC8h1TTL6bf3PA7LS woAcnE3Q0da6gdT3zAFgBXJ+ZLZEW7KpvEK+/W0ho7YcP7QIdhHKHUgdM/Imxozj3W lYBmvLiZPMl0cYHOcjPgAguK5OWkUHbv7a4D43fo= Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E3F4D6A858 for ; Fri, 1 May 2026 05:02:18 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1777633337; bh=6rM4TUyBT0IHvdcQ1RABxgeU0JT3jX7ohU0aPFLNFPw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lVZOZ6S42sHISQq4o3Rmcg9ZKDt/6SA0aeARlebkVd1T+O5gdTARi1oWepo1Lx7Jh aotBW7lt3Cv7Itc9m22T+pwyoZhuAHYGjOe/WiGwa4Qi/TvU10fdwh2dJD6Zm7W3U5 TyuPhRyMFl2/AFK6r9b7F6mTnDc9MQPLjojf9DAk= Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C0D276A84E; Fri, 1 May 2026 05:02:17 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id H9gylCIja5WA; Fri, 1 May 2026 05:02:17 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1777633333; bh=00z5vegfOPcaCnlbBNunw/9CmPhcowqwmfbxdyxYu6o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E/eRQYP50SU5TMX80gjVbUlcPDBcwlNBR9a9uFIU+YdcvYe87hsQSiX/fi1XEU8n4 ZyDwfZ6qX6Y4D6oyVA4kXR4ugX7WrX0DCHZrCznXWczLoVgvk4tyCexL2QiQKPk4UI Lzg7Q88u3tmLOKEbN4IpXNggV+qdAjmFmgJM5dbA= Received: from u-boot.org (unknown [174.51.25.52]) by mail.u-boot.org (Postfix) with ESMTPSA id AB7286A834; Fri, 1 May 2026 05:02:13 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 1 May 2026 05:00:20 -0600 Message-ID: <20260501110040.1874719-29-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260501110040.1874719-1-sjg@u-boot.org> References: <20260501110040.1874719-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 3DBMITNCB4T27I6TSIO52I2J5KYLDHZO X-Message-ID-Hash: 3DBMITNCB4T27I6TSIO52I2J5KYLDHZO X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 28/29] patman: Clarify the 'series not in database' error path List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Running 'patman series scan' on a branch that has not been added to the database fails with: patman: ValueError: No matching series for id None version 1 The same shape of confusing error -- a database lookup with idnum None being reported as raw SQL -- is reachable from 'series set-link', 'series get-link', 'series save-notes' and 'series show-notes' too, because each of those subcommands also passes ser.idnum on without checking that the series was actually found. Pull the existing 'if not ser.idnum: raise ValueError(...)' pattern out of the ten places it appears in cseries.py into a helper, _ensure_in_db(), in cser_helper.py. The helper raises a single canonical message that names the series and points at 'patman series add' as the fix: Series 'foo' not found in database; use 'patman series add' first Use the helper in every existing site (so the message is uniform across subcommands) and add it to the four sites that previously let an unset idnum reach the database. Update the two tests that asserted on the old per-site error wording ('No such series') to expect the unified message. Signed-off-by: Simon Glass --- tools/patman/cser_helper.py | 20 ++++++++++++++++++++ tools/patman/cseries.py | 32 ++++++++++++++------------------ tools/patman/test_cseries.py | 11 ++++++++--- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/tools/patman/cser_helper.py b/tools/patman/cser_helper.py index 032d5218e9e..0ce59e8ecc0 100644 --- a/tools/patman/cser_helper.py +++ b/tools/patman/cser_helper.py @@ -731,6 +731,26 @@ class CseriesHelper: recs = self.get_ser_ver(series_id, version) return recs.idnum, recs.link + def _ensure_in_db(self, ser): + """Verify a series object came from the database. + + Many subcommands look up a series by name, get a Series object back + with idnum unset when no row exists, then pass that idnum on to the + database where it is reported only as 'series_id NULL'. Raise a + clear ValueError up front so the caller knows to register the + series first. + + Args: + ser (Series): Series object whose idnum must be set + + Raises: + ValueError: if ser.idnum is None + """ + if not ser.idnum: + raise ValueError( + f"Series '{ser.name}' not found in database; " + "use 'patman series add' first") + def get_ser_ver(self, series_id, version): """Get the patchwork details for a series version diff --git a/tools/patman/cseries.py b/tools/patman/cseries.py index 443fe324c37..fb3f5a6c49a 100644 --- a/tools/patman/cseries.py +++ b/tools/patman/cseries.py @@ -126,8 +126,7 @@ class Cseries(cser_helper.CseriesHelper): dry_run (bool): True to do a dry run """ ser = self._parse_series(series) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) max_vers = self._series_max_version(ser.idnum) if max_vers < 2: @@ -170,8 +169,7 @@ class Cseries(cser_helper.CseriesHelper): dry_run (bool): True to do a dry run """ ser = self._parse_series(series_name) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) max_vers = self._series_max_version(ser.idnum) @@ -230,6 +228,7 @@ class Cseries(cser_helper.CseriesHelper): link """ ser, version = self._parse_series_and_version(series_name, version) + self._ensure_in_db(ser) self._ensure_version(ser, version) self._set_link(ser.idnum, ser.name, version, link, update_commit) @@ -248,6 +247,7 @@ class Cseries(cser_helper.CseriesHelper): str: Patchwork link as a string, e.g. '12325' """ ser, version = self._parse_series_and_version(series, version) + self._ensure_in_db(ser) self._ensure_version(ser, version) return self.db.ser_ver_get_link(ser.idnum, version) @@ -825,8 +825,7 @@ class Cseries(cser_helper.CseriesHelper): """ ser = self._parse_series(name) name = ser.name - if not ser.idnum: - raise ValueError(f"No such series '{name}'") + self._ensure_in_db(ser) self.db.ser_ver_remove(ser.idnum, None) if not dry_run: @@ -851,8 +850,7 @@ class Cseries(cser_helper.CseriesHelper): dry_run (bool): True to do a dry run """ old_ser, _ = self._parse_series_and_version(series, None) - if not old_ser.idnum: - raise ValueError(f"Series '{old_ser.name}' not found in database") + self._ensure_in_db(old_ser) if old_ser.name != series: raise ValueError(f"Invalid series name '{series}': " 'did you use the branch name?') @@ -922,6 +920,7 @@ class Cseries(cser_helper.CseriesHelper): notes = tools.read_file(notes_file, binary=False).strip() ser, version = self._parse_series_and_version(series, None) + self._ensure_in_db(ser) svid = self.get_series_svid(ser.idnum, version) self.db.ser_ver_set_notes(svid, notes) self.commit() @@ -934,6 +933,7 @@ class Cseries(cser_helper.CseriesHelper): series (str): Series name, or None for current branch """ ser, _ = self._parse_series_and_version(series, None) + self._ensure_in_db(ser) all_notes = self.db.ser_ver_get_all_notes(ser.idnum) if not all_notes: tout.notice(f"No review notes for '{ser.name}'") @@ -954,8 +954,7 @@ class Cseries(cser_helper.CseriesHelper): the listed patch numbers (1-based). """ ser, _ = self._parse_series_and_version(series, None) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) with terminal.pager(): self._show_info(ser, show_reviews) @@ -1058,8 +1057,7 @@ class Cseries(cser_helper.CseriesHelper): if not ups: raise ValueError('Please specify the upstream name') ser, _ = self._parse_series_and_version(series, None) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) self.db.series_set_upstream(ser.idnum, ups) @@ -1093,6 +1091,7 @@ class Cseries(cser_helper.CseriesHelper): tout.info(f'{oper} {seq:3} {out}') name, ser, version, msg = self.prep_series(branch_name, end) + self._ensure_in_db(ser) svid = self.get_ser_ver(ser.idnum, version).idnum pcdict = self.get_pcommit_dict(svid) @@ -1191,8 +1190,7 @@ class Cseries(cser_helper.CseriesHelper): succeed """ ser, version = self._parse_series_and_version(name, None) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) ups = self.get_series_upstream(name) if ups: @@ -1226,8 +1224,7 @@ class Cseries(cser_helper.CseriesHelper): series (str): Name of series to use, or None to use current branch """ ser = self._parse_series(series, include_archived=True) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) svlist = self.db.ser_ver_get_for_series(ser.idnum) @@ -1275,8 +1272,7 @@ class Cseries(cser_helper.CseriesHelper): series (str): Name of series to use, or None to use current branch """ ser = self._parse_series(series, include_archived=True) - if not ser.idnum: - raise ValueError(f"Series '{ser.name}' not found in database") + self._ensure_in_db(ser) self.db.series_set_archived(ser.idnum, False) svlist = self.db.ser_ver_get_for_series(ser.idnum) diff --git a/tools/patman/test_cseries.py b/tools/patman/test_cseries.py index c267b048fc5..7d6f99b3536 100644 --- a/tools/patman/test_cseries.py +++ b/tools/patman/test_cseries.py @@ -2384,7 +2384,10 @@ Tested-by: Mary Smith # yak with self.stage('remove non-existent series'): with self.assertRaises(ValueError) as exc: cser.remove('first') - self.assertEqual("No such series 'first'", str(exc.exception)) + self.assertEqual( + "Series 'first' not found in database; use " + "'patman series add' first", + str(exc.exception)) with self.stage('add'): with terminal.capture() as (out, _): @@ -2410,8 +2413,10 @@ Tested-by: Mary Smith # yak with terminal.capture() as (out, _): self.run_args('series', '-s', 'first', 'rm', expect_ret=1, pwork=True) - self.assertEqual("patman: ValueError: No such series 'first'", - out.getvalue().strip()) + self.assertEqual( + "patman: ValueError: Series 'first' not found in database;" + " use 'patman series add' first", + out.getvalue().strip()) with self.stage('add'): with terminal.capture() as (out, _):