From b35d61311c7a7fd3c88ddfb71f53d606fb992ddb Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Thu, 11 Jun 2026 11:55:19 +0200 Subject: [PATCH 1/4] App: Support --topdir-format "relative" The global --topdir-format option governs how a project's root directory is represented in paths output by various queries. "absolute" means as absolute path, "unaltered" means verbatim as specified via --topdir, make:xyz means replaced by the string $(xyz), for later expansion in a makefile variable. This commit adds another variant: "relative" yields the shortest possible output format of the output path in question relative to --topdir, with "shortest possible" in this context meaning canonicalized and leading "./" stripped. Signed-off-by: Jan Lindemann --- src/python/jw/pkg/App.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/python/jw/pkg/App.py b/src/python/jw/pkg/App.py index c7775ae5..a018fddb 100644 --- a/src/python/jw/pkg/App.py +++ b/src/python/jw/pkg/App.py @@ -83,6 +83,8 @@ class App(Base): match fmt: case 'unaltered': return path + case 'relative': + return os.path.relpath(path) case None | 'absolute': return os.path.abspath(path) case _: @@ -135,6 +137,8 @@ class App(Base): return os.path.abspath(pd) if self.__topdir_fmt == 'unaltered': return pd + if self.__topdir_fmt == 'relative': + return os.path.relpath(pd, self.__pretty_topdir) if name == self.__top_name: return self.__pretty_topdir raise NotImplementedError( @@ -151,7 +155,10 @@ class App(Base): if os.path.isdir(path): ret = format_pd(name, pd, pretty) if sd and sd[0] != '/': - ret += '/' + if ret == '.': + ret = '' + else: + ret += '/' ret += sd return ret for ret in search_absdirs: @@ -345,7 +352,7 @@ class App(Base): default = 'absolute', help = ( 'Output references to topdir as one of "make:", ' - '"unaltered", "absolute". Absolute topdir by default' + '"unaltered", "relative", "absolute". Absolute topdir by default' ), ) parser.add_argument( -- 2.54.0 From 46b1ce776ec9c8adc689c19f9439c3d2f53943a2 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Thu, 11 Jun 2026 11:56:11 +0200 Subject: [PATCH 2/4] cmds.projects.CmdPythonpath: Opts subdir, delimiter, prefix Support additional options: --subdir makes the command look for these existing subdirectories. Can be specified multiple times. --delimiter Does the obvious and defaults to ":" --prefix A string to prepend verbatim before each path component Signed-off-by: Jan Lindemann --- .../jw/pkg/cmds/projects/CmdPythonpath.py | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/python/jw/pkg/cmds/projects/CmdPythonpath.py b/src/python/jw/pkg/cmds/projects/CmdPythonpath.py index 9ddd6463..1b02a83b 100644 --- a/src/python/jw/pkg/cmds/projects/CmdPythonpath.py +++ b/src/python/jw/pkg/cmds/projects/CmdPythonpath.py @@ -1,8 +1,9 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from ...App import Scope from .Cmd import Cmd, Parent -from typing import TYPE_CHECKING if TYPE_CHECKING: from argparse import ArgumentParser, Namespace @@ -16,6 +17,25 @@ class CmdPythonpath(Cmd): # export def add_arguments(self, parser: ArgumentParser) -> None: super().add_arguments(parser) + parser.add_argument( + '--subdir', + action = 'append', + help = ( + 'Directories to look for relative to the ' + 'respective project root directory' + ), + default = ['src/python', 'tools/python'], + ) + parser.add_argument( + '--delimiter', + default = ':', + help = 'Delimiter between paths', + ) + parser.add_argument( + '--prefix', + help = 'Prefix to prepend before every path component', + dest = 'path_component_prefix', + ) parser.add_argument('module', help = 'Modules', nargs = '*') async def _run(self, args: Namespace) -> None: @@ -29,8 +49,10 @@ class CmdPythonpath(Cmd): # export ) out = [] for m in deps: - path = self.app.find_dir(m, ['src/python', 'tools/python']) + path = self.app.find_dir(m, args.subdir) if path is not None: + if args.path_component_prefix is not None: + path = f'{args.path_component_prefix}{path}' out.append(path) if out: - print(':'.join(out)) + print(args.delimiter.join(out)) -- 2.54.0 From c8fc6326cbde8e5005d4a9c17588a0ad713d3434 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Thu, 11 Jun 2026 11:57:01 +0200 Subject: [PATCH 3/4] py-topdir.mk: Use pythonpath --prefix for mypy_path Make use of the newly introduced --prefix option to the pythonpath command, and generate what's subseqently used to fill in mypy_path in pyproject.toml. By decoupling it from PYTHONPATH, this commit makes the creation of mypy_path less involved and easier to understand. It also obviates the need replace the relatively heavy ldlibpath.mk by the relatively lightweight projects.mk, thereby enhancing performance. Signed-off-by: Jan Lindemann --- make/py-topdir.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/py-topdir.mk b/make/py-topdir.mk index a58e1207..acbcb8aa 100644 --- a/make/py-topdir.mk +++ b/make/py-topdir.mk @@ -1,10 +1,10 @@ -include $(JWBDIR)/make/ldlibpath.mk +include $(JWBDIR)/make/projects.mk TD_GENERATE_FILES += pyproject.toml PY_CHECK_EXCLUDE ?= -MYPY_CONFIG_PATH = $(subst :,:$$MYPY_CONFIG_FILE_DIR/,:$(PYTHONPATH)) +MYPY_CONFIG_PATH = $(shell $(JW_PKG_PY) --topdir-format relative projects pythonpath --prefix '$$MYPY_CONFIG_FILE_DIR/' $(PROJECT)) MYPY_PATH_DIRECTIVE = mypy_path = "$(MYPY_CONFIG_PATH)" ifndef PY_CHECK_ROOTS -- 2.54.0 From f153a990a7b1158424bd0d7e4e497af0d31e7817 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Thu, 11 Jun 2026 12:36:06 +0200 Subject: [PATCH 4/4] build.cmds.CmdPythonpathOrig: Remove Remove CmdPythonpathOrig. Its only purpose has ever been to document and try out how cmd_pythonpath_orig() had worked in an ancient application version, that purpose is now served. Signed-off-by: Jan Lindemann --- .../jw/pkg/cmds/projects/CmdPythonpathOrig.py | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 src/python/jw/pkg/cmds/projects/CmdPythonpathOrig.py diff --git a/src/python/jw/pkg/cmds/projects/CmdPythonpathOrig.py b/src/python/jw/pkg/cmds/projects/CmdPythonpathOrig.py deleted file mode 100644 index 8a7bb2c8..00000000 --- a/src/python/jw/pkg/cmds/projects/CmdPythonpathOrig.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import annotations -import os - -from ...App import Scope -from .Cmd import Cmd, Parent -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from argparse import ArgumentParser, Namespace - -class CmdPythonpathOrig(Cmd): # export - - def __init__(self, parent: Parent) -> None: - super().__init__(parent, 'pythonpath_orig', help = 'pythonpath') - - def add_arguments(self, parser: ArgumentParser) -> None: - super().add_arguments(parser) - parser.add_argument('module', nargs = '*', help = 'Modules') - - async def _run(self, args: Namespace) -> None: - deps = self.app.get_project_refs( - args.module, - ['pkg.requires.jw'], - ['run', 'build'], - scope = Scope.Subtree, - add_self = True, - names_only = True, - ) - r = '' - for m in deps: - pd = self.app.find_dir(m, pretty = False) - if pd is None: - continue - for subdir in ['src/python', 'tools/python']: - cand = pd + '/' + subdir - if os.path.isdir(cand): - r = r + ':' + cand - print(r[1:]) -- 2.54.0