Improve Python config file template substitution #8

Merged
Jan Lindemann merged 10 commits from jan/feature/20260609-pyproject-toml-add-mypypath into master 2026-06-09 08:13:09 +02:00 AGit
Showing only changes of commit da877c624f - Show all commits

cmds.projects.CmdCreateFile: Add more options

- Add an additional, more generic value that --format understands: "tmpl". If chosen, the template selected by the new option --template-name is rendered by replacing --field key=value pairs.
- This commit also adds the option --quote, which makes the renderer enclose the rendered variable values in double quotes.
Signed-off-by: Jan Lindemann <jan@janware.com>
Jan Lindemann 2026-06-04 07:29:29 +02:00
Signed by: Jan Lindemann
GPG key ID: 3750640C9E25DD61

View file

@ -1,11 +1,10 @@
from argparse import ArgumentParser, ArgumentTypeError, Namespace from argparse import ArgumentParser, ArgumentTypeError, Namespace
from enum import Enum, auto from enum import Enum, auto
from typing import Iterable, TypeAlias
from ...lib.log import WARNING, log from ...lib.log import WARNING, log
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
from .lib.pkg_relations import VersionSyntax, pkg_relations from .lib.pkg_relations import VersionSyntax, pkg_relations
from .lib.templates import RenderValues, tmpl_render from .lib.templates import ListDict, RenderValues, tmpl_render
def key_value(s): def key_value(s):
try: try:
@ -18,24 +17,26 @@ def key_value(s):
class Fmt(Enum): class Fmt(Enum):
Pyright = auto() Pyright = auto()
TupleList: TypeAlias = Iterable[tuple[str, str]]
ListDict: TypeAlias = dict[str, list[str]]
class CmdCreateFile(Cmd): # export class CmdCreateFile(Cmd): # export
def __tuple_list_to_dict(self, src: TupleList) -> ListDict: def __jw_required(self, module: str | None = None) -> list[str]:
ret: ListDict = {} if module is None:
for key, val in src: module = self.app.args.module
entry = ret.setdefault(key, []) if module is None:
entry.append(val) raise Exception('Can\'t get required packages without module name')
return ret return pkg_relations(
self.app,
def __update_dict(self, dst: ListDict, src: TupleList) -> ListDict: rel_type = 'requires',
ret = dst flavours = ['run'],
for key, val in src: subsections = ['jw'],
entry = ret.setdefault(key, []) seed_pkgs = [module],
entry.append(val) syntax = VersionSyntax.names_only,
return ret no_subpackages = True,
recursive = True,
quote = False,
hide_self = False,
hide_jw_pkg = False,
)
def __render( def __render(
self, self,
@ -52,23 +53,19 @@ class CmdCreateFile(Cmd): # export
search_path = self.app.args.search_path.split(':'), search_path = self.app.args.search_path.split(':'),
) )
def render_pyright(self, module: str, extra_fields: TupleList) -> str: def render_tmpl(self, module: str, extra_fields: RenderValues) -> str:
prereq = pkg_relations( template_name = self.app.args.template_name
self.app, if template_name is None:
rel_type = 'requires', raise Exception('Can\'t render template without name')
flavours = ['run'], return self.__render(
subsections = ['jw'], template_name, [extra_fields],
seed_pkgs = [module], li_quote = self.app.args.quote,
syntax = VersionSyntax.names_only, li_delimiter = ',\n'
no_subpackages = True,
recursive = True,
quote = False,
hide_self = False,
hide_jw_pkg = False,
) )
def render_pyright(self, module: str, extra_fields: RenderValues) -> str:
extra_paths = [] extra_paths = []
for m in prereq: for m in self.__jw_required():
path = self.app.find_dir(m, search_subdirs = ['src/python', 'tools/python']) path = self.app.find_dir(m, search_subdirs = ['src/python', 'tools/python'])
if path is None: if path is None:
log(WARNING, f'No project directory for module "{m}"') log(WARNING, f'No project directory for module "{m}"')
@ -77,10 +74,10 @@ class CmdCreateFile(Cmd): # export
values: ListDict = { values: ListDict = {
'extra_paths': extra_paths, 'extra_paths': extra_paths,
} }
self.__update_dict(values, extra_fields)
return self.__render( return self.__render(
'pyrightconfig.json', [values], li_quote = True, li_delimiter = ',\n' 'pyrightconfig.json', [values, extra_fields],
li_quote = True,
li_delimiter = ',\n'
) )
def __init__(self, parent: Parent) -> None: def __init__(self, parent: Parent) -> None:
@ -92,14 +89,22 @@ class CmdCreateFile(Cmd): # export
super().add_arguments(parser) super().add_arguments(parser)
parser.add_argument( parser.add_argument(
'--format', '--format',
choices = [fmt.name.lower() for fmt in Fmt], help = (
help = 'Output format' 'Output format, for example: '
', '.join([fmt.name.lower() for fmt in Fmt])
)
) )
parser.add_argument( parser.add_argument(
'--search-path', '--search-path',
default = '/etc/opt/jw-pkg/templates', default = '/etc/opt/jw-pkg/templates',
help = 'Template search path, colon separated', help = 'Template search path, colon separated',
) )
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'
)
parser.add_argument( parser.add_argument(
'-f', '-f',
'--field', '--field',