From fc6f2fbb65adf67c0a136613106b0571b0b6e142 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Sat, 30 May 2026 09:00:04 +0200 Subject: [PATCH] python-tools.sh: Fix __init__.py linter complaints The __init__.py files as gnerated by python-tools.sh contain multiple issues, fix them: - Make the machinery fail if the same type name is imported from different modules - Support relative imports from .Module import Module instead of having to use the entire module path as import source - Import types explicitly re-exported with "as": from .Module import Module as Module Otherwise ruff will regard the type as "imported but not used" - Add "# ruff: noqa: E501" near the top. The import lines can get long and are beyond manual control (except for renaming the modules themselves, that is). This can cause ruff to fail, so get it to accept long lines in __init__.py. The style violation doesn't make much of a difference in generated code, anyway, because nobody reads that. Plus what's happening in the code isn't rocket science, so good style wouldn't help much with understanding, either. This promptly digs up two symbol name conflicts lib.pm.dpkg and lib.pm.rpm. Fix them along with this commit to keep it from breaking the build. Signed-off-by: Jan Lindemann --- make/py-mod.mk | 2 +- scripts/python-tools.sh | 40 +++++++++++++++++++++----------- src/python/jw/pkg/lib/pm/dpkg.py | 4 ++-- src/python/jw/pkg/lib/pm/rpm.py | 4 ++-- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/make/py-mod.mk b/make/py-mod.mk index b14e2845..c7819114 100644 --- a/make/py-mod.mk +++ b/make/py-mod.mk @@ -20,7 +20,7 @@ include $(JWBDIR)/make/py-rules.mk ifeq ($(PY_UPDATE_INIT_PY),true) __init__.py: $(PY_INIT_TMPL) $(filter-out __init__.py,$(PY_SRC_PY)) if [ "$(PY_INIT_TMPL)" ]; then cat "$(PY_INIT_TMPL)" > $@.tmp; else > $@.tmp; fi - /bin/bash +H $(JWB_SCRIPT_DIR)/python-tools.sh create-init -m $(PY_MOD) -e "$(PY_SED_EXTRACT_EXPORT)" \ + set -e -o pipefail; /bin/bash $(JWB_SCRIPT_DIR)/python-tools.sh create-init -m . -e "$(PY_SED_EXTRACT_EXPORT)" \ $(filter-out __init__.py,$(PY_ALL_PY)) $(SUBDIRS_TO_ITERATE) | $(PY_INIT_FILTER) | tee -a $@.tmp mv $@.tmp $@ endif diff --git a/scripts/python-tools.sh b/scripts/python-tools.sh index 543571fe..97956c10 100644 --- a/scripts/python-tools.sh +++ b/scripts/python-tools.sh @@ -1,5 +1,16 @@ #!/bin/bash +log() +{ + echo "$myname: $*" >&2 +} + +fatal() +{ + echo "$myname: Fatal: $*" >&2 + exit 1 +} + usage() { cat <<-EOT @@ -12,33 +23,36 @@ usage() module_path() { - if [ "$module" ]; then + if [ "$module" = "." ]; then + echo .$1 + elif [ "$module" ]; then echo $module.$1 - return + else + echo $1 fi - echo $1 } cmd_create_init() { local import_submodules=0 - local e f files base extracted module_path + local files="$*" local del="-------------------------- generated by $myname" echo "# >> $del >>" + echo "# ruff: noqa: E501" echo "from pkgutil import extend_path" - echo "from typing import Iterable" - echo "__path__ = extend_path(__path__, __name__) # type: ignore" # was "type Iterable[str]" - files="$*" + echo "__path__ = extend_path(__path__, __name__)" + local f + local -A seen=() for f in $files; do test -d $f && continue - base=${f##*/} + local base=${f##*/} base=${base%.py} if [ "$sed_extract_command" ]; then - #echo running $sed_extract_command on $f - extracted=`sed "$sed_extract_command" $f` - #extracted="$sed_extract_command" - for e in $extracted; do - echo "from `module_path $base` import $e" + local type types=`sed "$sed_extract_command" $f` + for type in $types; do + echo "from `module_path $base` import $type as $type" + [[ -n "${seen[$type]+x}" ]] && fatal "Duplicate symbol: $type" + seen["$type"]=1 done fi done diff --git a/src/python/jw/pkg/lib/pm/dpkg.py b/src/python/jw/pkg/lib/pm/dpkg.py index 3ff2a9c0..88074d87 100644 --- a/src/python/jw/pkg/lib/pm/dpkg.py +++ b/src/python/jw/pkg/lib/pm/dpkg.py @@ -39,12 +39,12 @@ async def run_dpkg_query(args: list[str], sudo: bool=False, ec: ExecContext=None return await run_sudo(cmd) return (await run_cmd(cmd, ec=ec, cmd_input=InputMode.NonInteractive)).decode() -async def query_packages(names: Iterable[str] = [], ec: ExecContext=None) -> Iterable[Package]: # export +async def query_packages(names: Iterable[str] = [], ec: ExecContext=None) -> Iterable[Package]: fmt_str = '|'.join([(f'${{{tag}}}' if tag else '') for tag in meta_map().values()]) + r'\n' # dpkg-query -W -f='${binary:Package}|${Maintainer}| ... \n' specs, stderr, status = await run_dpkg_query(['-W', '-f=' + fmt_str, *names], sudo=False, ec=ec) return Package.parse_specs_str(specs) -async def list_files(pkg: str, ec: ExecContext=None) -> list[str]: # export +async def list_files(pkg: str, ec: ExecContext=None) -> list[str]: file_list_str, stderr, status = await run_dpkg(['-L', pkg], sudo=False, ec=ec) return file_list_str.splitlines() diff --git a/src/python/jw/pkg/lib/pm/rpm.py b/src/python/jw/pkg/lib/pm/rpm.py index 54d1b94c..24f36f49 100644 --- a/src/python/jw/pkg/lib/pm/rpm.py +++ b/src/python/jw/pkg/lib/pm/rpm.py @@ -32,7 +32,7 @@ async def run_rpm(args: list[str], sudo: bool=False, ec: ExecContext=None, mode: return await run_sudo(cmd, ec=ec, cmd_input=mode, **kwargs) return await run_cmd(cmd, ec=ec, cmd_input=mode, **kwargs) -async def query_packages(names: Iterable[str] = [], ec: ExecContext=None) -> Iterable[Package]: # export +async def query_packages(names: Iterable[str] = [], ec: ExecContext=None) -> Iterable[Package]: fmt_str = '|'.join([(f'%{{{tag}}}' if tag else '') for tag in meta_map().values()]) + r'\n' opts = ['-q', '--queryformat', fmt_str] if not names: @@ -40,6 +40,6 @@ async def query_packages(names: Iterable[str] = [], ec: ExecContext=None) -> Ite specs, stderr, status = await run_rpm([*opts, *names], throw=True, sudo=False, mode=InputMode.NonInteractive, ec=ec) return Package.parse_specs_str(specs.decode()) -async def list_files(pkg: str, ec: ExecContext=None) -> list[str]: # export +async def list_files(pkg: str, ec: ExecContext=None) -> list[str]: stdout, stderr, status = await run_rpm(['-ql', pkg], throw=True, sudo=False, mode=InputMode.NonInteractive, ec=ec) return stdout.decode().splitlines()