App, cmds, lib: Fix Any returns from typed functions

Add type annotations and casts to functions that were returning Any
where a specific type was declared, satisfying the new warn_return_any
mypy rule.

Fixes:
- log.py: get_caller_pos return type via cast
- AsyncRunner.py: cast T for fut.result()
- util.py: cast for getattr result, str() for args.username
- FileContext.py: verbose_default bool annotation
- SSHClient.py: cast SSHClient for dynamic import
- lib/App.py: cast ArgumentParser, add return types to inner funcs
- pm/rpm.py, dpkg.py: cast Iterable[Package]
- App.py: cast for self.args.func(), add return types to inner funcs
- BaseCmdPkgRelations.py: cast str for args.delimiter

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-07-22 23:03:53 +02:00
commit 1e613a39c6
40 changed files with 228 additions and 179 deletions

View file

@ -6,7 +6,7 @@ import os
import sys
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace
from typing import override, TYPE_CHECKING, Any
from typing import Any, cast, override, TYPE_CHECKING
from .AsyncRunner import AsyncRunner
from .log import DEBUG, ERR, NOTICE, log, log_m, set_log_flags, set_log_level
@ -52,12 +52,15 @@ class App: # export
) -> None:
def add_cmd_to_parser(cmd: AbstractCmd, parsers: Any) -> ArgumentParser:
parser = parsers.add_parser(
cmd.name,
help = cmd.help,
description = cmd.description,
aliases = cmd.aliases,
formatter_class = ArgumentDefaultsHelpFormatter,
parser = cast(
'ArgumentParser',
parsers.add_parser(
cmd.name,
help = cmd.help,
description = cmd.description,
aliases = cmd.aliases,
formatter_class = ArgumentDefaultsHelpFormatter,
)
)
parser.set_defaults(func = cmd.run)
cmd.add_arguments(parser)
@ -68,7 +71,7 @@ class App: # export
parent: AbstractCmd | App,
parser: ArgumentParser,
cmds: Collection[AbstractCmd],
all = False
all: bool = False
) -> None:
if not cmds:
return
@ -168,7 +171,7 @@ class App: # export
'-h', '--help', action = 'help', help = 'Show this help message and exit'
)
def __del__(self):
def __del__(self) -> None:
if self.__own_eloop:
if self.__eloop is not None:
self.__eloop.close()
@ -178,10 +181,10 @@ class App: # export
async def __aenter__(self) -> None:
pass
async def __aexit__(self, exc_type, exc, tb) -> None:
async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
pass
async def __run(self, argv = None) -> None:
async def __run(self, argv: list[str] | None = None) -> None:
try:
# Import argcomplete only here to not require it to be compatible
@ -194,8 +197,8 @@ class App: # export
@override
def __call__( # pyright: ignore[reportGeneralTypeIssues]
self, *args, **kwargs
):
self, *args: Any, **kwargs: Any
) -> None:
return None
import argcomplete # type: ignore[import-not-found, unused-ignore]
@ -249,7 +252,7 @@ class App: # export
self.__parser.print_help()
return None
# Run sub-command. Overwrite if you want to do anything before or after
return await self.args.func(args)
return cast('None | int', await self.args.func(args))
def call_async(self, awaitable: Awaitable[T], timeout: float | None = None) -> T:
return self.async_runner.call(awaitable, timeout)
@ -286,7 +289,7 @@ class App: # export
def parser(self) -> ArgumentParser:
return self.__parser
def run(self, argv = None) -> None:
def run(self, argv: list[str] | None = None) -> None:
try:
ret = self.eloop.run_until_complete(self.__run(argv))
finally:
@ -296,7 +299,10 @@ class App: # export
return ret
def run_sub_commands( # export
description = '', name_filter = '^Cmd.*', modules = None, argv = None
):
description: str = '',
name_filter: str = '^Cmd.*',
modules: list[str] | None = None,
argv: list[str] | None = None,
) -> None:
app = App(description, name_filter, modules)
return app.run(argv = argv)
app.run(argv = argv)