Package: depthcharge-tools
Version: 0.6.2-4
Severity: serious
Tags: d-i
Justification: working depthchargectl invokations break all of a sudden, breaks d-i
X-Debbugs-Cc: debian-boot@lists.debian.org, debian-kernel@lists.debian.org, reproducible-builds@lists.alioth.debian.org
Hi,
The python3-defaults package was just switched from 3.13 to 3.14 and
that breaks debian-installer builds. Previously, that's been working
fine for a very long time:
update-manifest dest/cdrom/gtk/debian-cd_info.tar.gz "isolinux help screens for CD (graphical)"
pigz -nm -v -d <tmp/cdrom_gtk/initrd.gz | xz -T0 --check=crc32 --block-size=1M -v >tmp/cdrom_gtk/initrd.xz
<stdin> to <stdout>
(stdin): 57.1 MiB / 134.4 MiB = 0.425, 14 MiB/s, 0:09
rm -f ./tmp/cdrom_gtk/depthcharge/*
mkdir -p ./tmp/cdrom_gtk/depthcharge
for board in amd64-generic; do \
depthchargectl build -v \
--board ${board} \
--kernel-release 7.0.13+deb14-amd64 \
--kernel ./tmp/cdrom_gtk/vmlinuz \
--initramfs ./tmp/cdrom_gtk/initrd.xz \
--root none \
--kernel-cmdline "partman-partitioning/default_label=gpt --- quiet" \
--output ./tmp/cdrom_gtk/depthcharge/${board}.kernel.img; \
gen-hd-image -v -z \
-X gpt \
-p $(($(stat -c%s ./tmp/cdrom_gtk/depthcharge/${board}.kernel.img) / 512 + 2048)) \
-i $(mktemp -d) \
-o ./tmp/cdrom_gtk/depthcharge/${board}.disk.img \
-d FE3A2A5D-4F32-41A7-B725-ACCC3285A309 \
./tmp/cdrom_gtk/depthcharge/${board}.kernel.img \
2048; \
pigz -9nmf ./tmp/cdrom_gtk/depthcharge/${board}.kernel.img; \
done
Couldn't find /boot in fstab, falling back to '/boot'.
Assuming board 'Unnamed amd64-generic board' ('amd64-generic') by codename argument or config.
Using kernel cmdline from given options: partman-partitioning/default_label=gpt --- quiet
Building depthcharge image for board 'Unnamed amd64-generic board' ('amd64-generic').
Building for kernel version '7.0.13+deb14-amd64'.
Trying with compression 'none'.
Using file '/build/reproducible-path/debian-installer-20250804/build/tmp/cdrom_gtk/vmlinuz' as a vmlinuz.
Trying to decompress file '/build/reproducible-path/debian-installer-20250804/build/tmp/cdrom_gtk/vmlinuz'.
Using file '/build/reproducible-path/debian-installer-20250804/build/tmp/cdrom_gtk/initrd.xz' as an initramfs.
Using keyblock file '/usr/share/vboot/devkeys/kernel.keyblock'.
Using signprivate file '/usr/share/vboot/devkeys/kernel_data_key.vbprivk'.
Using signpubkey file '/usr/share/vboot/devkeys/kernel_subkey.vbpubk'.
Vmlinuz pref_address is 0x1000000, with init_size 0x3c47000.
Padding vmlinuz to size 0xdaa000
Packing files as temporary image.
[…]
That broke all of a sudden with a traceback:
update-manifest dest/cdrom/gtk/debian-cd_info.tar.gz "isolinux help screens for CD (graphical)"
pigz -nm -v -d <tmp/cdrom_gtk/initrd.gz | xz -T0 --check=crc32 --block-size=1M -v >tmp/cdrom_gtk/initrd.xz
<stdin> to <stdout>
(stdin): 57.1 MiB / 134.4 MiB = 0.425, 14 MiB/s, 0:09
rm -f ./tmp/cdrom_gtk/depthcharge/*
mkdir -p ./tmp/cdrom_gtk/depthcharge
for board in amd64-generic; do \
depthchargectl build -v \
--board ${board} \
--kernel-release 7.0.13+deb14-amd64 \
--kernel ./tmp/cdrom_gtk/vmlinuz \
--initramfs ./tmp/cdrom_gtk/initrd.xz \
--root none \
--kernel-cmdline "partman-partitioning/default_label=gpt --- quiet" \
--output ./tmp/cdrom_gtk/depthcharge/${board}.kernel.img; \
gen-hd-image -v -z \
-X gpt \
-p $(($(stat -c%s ./tmp/cdrom_gtk/depthcharge/${board}.kernel.img) / 512 + 2048)) \
-i $(mktemp -d) \
-o ./tmp/cdrom_gtk/depthcharge/${board}.disk.img \
-d FE3A2A5D-4F32-41A7-B725-ACCC3285A309 \
./tmp/cdrom_gtk/depthcharge/${board}.kernel.img \
2048; \
pigz -9nmf ./tmp/cdrom_gtk/depthcharge/${board}.kernel.img; \
done
→ Traceback (most recent call last):
→ file "/usr/bin/depthchargectl", line 33, in <module>
→ sys.exit(load_entry_point('depthcharge-tools==0.6.2', 'console_scripts', 'depthchargectl')())
→ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
→ File "/usr/lib/python3/dist-packages/depthcharge_tools/utils/argparse.py", line 895, in main
→ parser = cls.parser
→ ^^^^^^^^^^
→ File "/usr/lib/python3/dist-packages/depthcharge_tools/utils/argparse.py", line 1042, in parser
→ return cls.__build()
→ ~~~~~~~~~~~^^
→ File "/usr/lib/python3/dist-packages/depthcharge_tools/utils/argparse.py", line 1065, in __build
→ arg.build(parser)
→ ~~~~~~~~~^^^^^^^^
→ File "/usr/lib/python3/dist-packages/depthcharge_tools/utils/argparse.py", line 439, in build
→ return parent.add_argument(*option_strings, **kwargs)
→ ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
→ File "/usr/lib/python3.14/argparse.py", line 1531, in add_argument
→ kwargs = self._get_positional_kwargs(*args, **kwargs)
→ File "/usr/lib/python3.14/argparse.py", line 1666, in _get_positional_kwargs
→ raise ValueError('nargs for positionals must be != 0')
→ ValueError: nargs for positionals must be != 0
stat: cannot statx './tmp/cdrom_gtk/depthcharge/amd64-generic.kernel.img': No such file or directory
/bin/sh: 10: arithmetic expression: expecting primary: " / 512 + 2048"
make[4]: *** [config/x86.cfg:437: arch_depthcharge] Error 2
make[3]: *** [Makefile:315: _build] Error 2
make[2]: *** [Makefile:309: build_cdrom_gtk] Error 2
make[1]: *** [Makefile:315: _build] Error 2
make: *** [Makefile:309: build_cdrom_isolinux] Error 2
(The parts after the traceback can be ignored, that's definitely a
problem in the installer's Makefile.)
I didn't immediately spot a breaking change in the “what's new in 3.14”
page, or the argparse documentation, but a quick search in CPython's git
repository quickly returned the following:
commit 9944ad388c457325456152257b977410c4ec3593
Author: Serhiy Storchaka <storchaka@gmail.com>
Date: Sat Oct 12 16:04:17 2024 +0300
gh-85935: Check for nargs=0 for positional arguments in argparse (GH-124839)
Raise ValueError in add_argument() if either explicit nargs=0 or action
that does not consume arguments (like 'store_const' or 'store_true') is
specified for positional argument.
diff --git a/Lib/argparse.py b/Lib/argparse.py
index cbecb3b753c..550415dc934 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1441,11 +1441,17 @@ def add_argument(self, *args, **kwargs):
kwargs['default'] = self.argument_default
# create the action object, and add it to the parser
+ action_name = kwargs.get('action')
action_class = self._pop_action_class(kwargs)
if not callable(action_class):
raise ValueError('unknown action "%s"' % (action_class,))
action = action_class(**kwargs)
+ # raise an error if action for positional argument does not
+ # consume arguments
+ if not action.option_strings and action.nargs == 0:
+ raise ValueError(f'action {action_name!r} is not valid for positional arguments')
+
# raise an error if the action type is not callable
type_func = self._registry_get('type', action.type, action.type)
if not callable(type_func):
@@ -1554,7 +1560,9 @@ def _get_positional_kwargs(self, dest, **kwargs):
# mark positional arguments as required if at least one is
# always required
nargs = kwargs.get('nargs')
- if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS, 0]:
+ if nargs == 0:
+ raise ValueError('nargs for positionals must be != 0')
+ if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS]:
kwargs['required'] = True
# return the keyword arguments with no option strings
And that's be consistent with the 3.13 versus 3.14 hypothesis:
kibi@tokyo:~/hack/cpython.git (main =)$ git describe --contains --tags 9944ad388c457325456152257b977410c4ec3593
v3.14.0a1~62
Cheers,