2026-05-27 15:46:00 +02:00
|
|
|
from argparse import ArgumentParser, ArgumentTypeError, Namespace
|
|
|
|
|
from enum import Enum, auto
|
App, lib, cmds: Fix mypy.explicit-override fallout
This commit adds @override decorators to approximately 300 methods
across 76 files that inherit from base classes such as AbstractCmd,
FileContext, ExecContext, Distro, SSHClient, and others.
The decorator ensures the type checker can verify that overridden
methods have compatible signatures and prevents accidental shadowing
of inherited methods without intent.
Files modified include command classes, library modules, distro
implementations, and SSH client implementations.
Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL with pi.dev v
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-07-22 15:51:14 +02:00
|
|
|
from typing import override
|
2026-05-27 15:46:00 +02:00
|
|
|
|
|
|
|
|
from ...lib.log import WARNING, log
|
|
|
|
|
from .Cmd import Cmd, Parent
|
|
|
|
|
from .lib.pkg_relations import VersionSyntax, pkg_relations
|
2026-06-04 07:29:29 +02:00
|
|
|
from .lib.templates import ListDict, RenderValues, tmpl_render
|
2026-05-27 15:46:00 +02:00
|
|
|
|
|
|
|
|
def key_value(s):
|
|
|
|
|
try:
|
|
|
|
|
key, value = s.split('=', 1)
|
|
|
|
|
except ValueError:
|
|
|
|
|
raise ArgumentTypeError('Expected KEY=VALUE')
|
|
|
|
|
return key, value
|
|
|
|
|
|
|
|
|
|
# TODO: Put the more elaborate stuff into lib
|
|
|
|
|
class Fmt(Enum):
|
|
|
|
|
Pyright = auto()
|
|
|
|
|
|
|
|
|
|
class CmdCreateFile(Cmd): # export
|
|
|
|
|
|
2026-07-10 19:06:32 +02:00
|
|
|
def __jw_required(
|
|
|
|
|
self,
|
|
|
|
|
*,
|
|
|
|
|
module: str | None = None,
|
|
|
|
|
include_self: bool = False,
|
|
|
|
|
) -> list[str]:
|
2026-06-04 07:29:29 +02:00
|
|
|
if module is None:
|
|
|
|
|
module = self.app.args.module
|
|
|
|
|
if module is None:
|
|
|
|
|
raise Exception('Can\'t get required packages without module name')
|
2026-07-10 19:06:32 +02:00
|
|
|
ret = pkg_relations(
|
2026-06-04 07:29:29 +02:00
|
|
|
self.app,
|
|
|
|
|
rel_type = 'requires',
|
|
|
|
|
flavours = ['run'],
|
|
|
|
|
subsections = ['jw'],
|
|
|
|
|
seed_pkgs = [module],
|
|
|
|
|
syntax = VersionSyntax.names_only,
|
|
|
|
|
no_subpackages = True,
|
|
|
|
|
recursive = True,
|
|
|
|
|
quote = False,
|
|
|
|
|
hide_self = False,
|
|
|
|
|
hide_jw_pkg = False,
|
|
|
|
|
)
|
2026-07-10 19:06:32 +02:00
|
|
|
if include_self and module not in ret:
|
|
|
|
|
ret = [module, *ret]
|
|
|
|
|
return ret
|
2026-05-27 15:46:00 +02:00
|
|
|
|
2026-06-02 21:18:21 +02:00
|
|
|
def __render(
|
|
|
|
|
self,
|
|
|
|
|
template_name: str,
|
|
|
|
|
values: list[RenderValues],
|
|
|
|
|
li_quote = False,
|
|
|
|
|
li_delimiter = '\n',
|
|
|
|
|
) -> str:
|
|
|
|
|
return tmpl_render(
|
|
|
|
|
template_name,
|
|
|
|
|
values,
|
|
|
|
|
li_quote = li_quote,
|
|
|
|
|
li_delimiter = li_delimiter,
|
|
|
|
|
search_path = self.app.args.search_path.split(':'),
|
|
|
|
|
)
|
|
|
|
|
|
2026-06-04 07:29:29 +02:00
|
|
|
def render_tmpl(self, module: str, extra_fields: RenderValues) -> str:
|
|
|
|
|
template_name = self.app.args.template_name
|
|
|
|
|
if template_name is None:
|
|
|
|
|
raise Exception('Can\'t render template without name')
|
|
|
|
|
return self.__render(
|
|
|
|
|
template_name, [extra_fields],
|
|
|
|
|
li_quote = self.app.args.quote,
|
|
|
|
|
li_delimiter = ',\n'
|
2026-05-27 15:46:00 +02:00
|
|
|
)
|
|
|
|
|
|
2026-06-04 07:29:29 +02:00
|
|
|
def render_pyright(self, module: str, extra_fields: RenderValues) -> str:
|
2026-05-27 15:46:00 +02:00
|
|
|
extra_paths = []
|
2026-07-10 19:06:32 +02:00
|
|
|
for m in self.__jw_required(include_self = True):
|
2026-06-05 15:02:56 +02:00
|
|
|
path = self.app.find_dir(m, search_subdirs = ['src/python', 'tools/python'])
|
2026-05-27 15:46:00 +02:00
|
|
|
if path is None:
|
|
|
|
|
log(WARNING, f'No project directory for module "{m}"')
|
|
|
|
|
continue
|
|
|
|
|
extra_paths.append(path)
|
2026-06-02 20:20:27 +02:00
|
|
|
values: ListDict = {
|
|
|
|
|
'extra_paths': extra_paths,
|
2026-05-27 15:46:00 +02:00
|
|
|
}
|
2026-06-02 21:18:21 +02:00
|
|
|
return self.__render(
|
2026-06-04 07:29:29 +02:00
|
|
|
'pyrightconfig.json', [values, extra_fields],
|
|
|
|
|
li_quote = True,
|
|
|
|
|
li_delimiter = ',\n'
|
2026-05-27 15:46:00 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent: Parent) -> None:
|
|
|
|
|
super().__init__(
|
|
|
|
|
parent, 'create-file', help = 'Generate a file from project metadata'
|
|
|
|
|
)
|
|
|
|
|
|
App, lib, cmds: Fix mypy.explicit-override fallout
This commit adds @override decorators to approximately 300 methods
across 76 files that inherit from base classes such as AbstractCmd,
FileContext, ExecContext, Distro, SSHClient, and others.
The decorator ensures the type checker can verify that overridden
methods have compatible signatures and prevents accidental shadowing
of inherited methods without intent.
Files modified include command classes, library modules, distro
implementations, and SSH client implementations.
Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL with pi.dev v
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-07-22 15:51:14 +02:00
|
|
|
@override
|
2026-05-27 15:46:00 +02:00
|
|
|
def add_arguments(self, parser: ArgumentParser) -> None:
|
|
|
|
|
super().add_arguments(parser)
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
'--format',
|
2026-06-04 07:29:29 +02:00
|
|
|
help = (
|
|
|
|
|
'Output format, for example: '
|
|
|
|
|
', '.join([fmt.name.lower() for fmt in Fmt])
|
|
|
|
|
)
|
2026-05-27 15:46:00 +02:00
|
|
|
)
|
2026-06-02 21:18:21 +02:00
|
|
|
parser.add_argument(
|
|
|
|
|
'--search-path',
|
|
|
|
|
default = '/etc/opt/jw-pkg/templates',
|
|
|
|
|
help = 'Template search path, colon separated',
|
|
|
|
|
)
|
2026-06-04 07:29:29 +02:00
|
|
|
parser.add_argument('--template-name', help = 'Template file name')
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
'--quote',
|
|
|
|
|
action = 'store_true',
|
|
|
|
|
help = 'Enclose variable values in double quotes before substituting'
|
|
|
|
|
)
|
2026-05-27 15:46:00 +02:00
|
|
|
parser.add_argument(
|
|
|
|
|
'-f',
|
|
|
|
|
'--field',
|
|
|
|
|
action = 'append',
|
|
|
|
|
type = key_value,
|
|
|
|
|
default = [],
|
|
|
|
|
metavar = 'KEY=VALUE',
|
|
|
|
|
help = 'Additional fields to insert into the output file',
|
|
|
|
|
)
|
|
|
|
|
parser.add_argument('module', help = 'The module to generate the file for')
|
|
|
|
|
|
App, lib, cmds: Fix mypy.explicit-override fallout
This commit adds @override decorators to approximately 300 methods
across 76 files that inherit from base classes such as AbstractCmd,
FileContext, ExecContext, Distro, SSHClient, and others.
The decorator ensures the type checker can verify that overridden
methods have compatible signatures and prevents accidental shadowing
of inherited methods without intent.
Files modified include command classes, library modules, distro
implementations, and SSH client implementations.
Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL with pi.dev v
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-07-22 15:51:14 +02:00
|
|
|
@override
|
2026-05-27 15:46:00 +02:00
|
|
|
async def _run(self, args: Namespace) -> None:
|
|
|
|
|
method = getattr(self, 'render_' + args.format, None)
|
|
|
|
|
if method is None: # Should be prevented by choices=[] but keeps linter happy
|
|
|
|
|
raise Exception(f'Unsupported output format {args.format}')
|
|
|
|
|
print(method(args.module, args.field))
|