Skip to content

Commit 30b3989

Browse files
committed
app: main: support custom tools
Add support for loading tools from the custom tools path. Signed-off-by: Jordan Yates <jordan@embeint.com>
1 parent e9fdec2 commit 30b3989

1 file changed

Lines changed: 33 additions & 12 deletions

File tree

src/infuse_iot/app/main.py

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88

99
import argparse
1010
import importlib.util
11+
import pathlib
1112
import pkgutil
1213
import sys
14+
import types
1315

1416
import argcomplete
1517

1618
import infuse_iot.tools
1719
from infuse_iot.commands import InfuseCommand
20+
from infuse_iot.credentials import get_custom_tool_path
1821
from infuse_iot.version import __version__
1922

2023

@@ -38,24 +41,42 @@ def run(self, argv):
3841
tool = self.args.tool_class(self.args)
3942
tool.run()
4043

44+
def _load_from_module(self, parent_parser: argparse._SubParsersAction, module: types.ModuleType):
45+
tool_cls: InfuseCommand = module.SubCommand
46+
parser = parent_parser.add_parser(
47+
tool_cls.NAME,
48+
help=tool_cls.HELP,
49+
description=tool_cls.DESCRIPTION,
50+
formatter_class=argparse.RawDescriptionHelpFormatter,
51+
)
52+
parser.set_defaults(tool_class=tool_cls)
53+
tool_cls.add_parser(parser)
54+
4155
def _load_tools(self, parser: argparse.ArgumentParser):
4256
tools_parser = parser.add_subparsers(title="commands", metavar="<command>", required=True)
4357

44-
# Iterate over tools
58+
# Iterate over local tools
4559
for _, name, _ in pkgutil.walk_packages(infuse_iot.tools.__path__):
4660
full_name = f"{infuse_iot.tools.__name__}.{name}"
4761
module = importlib.import_module(full_name)
48-
49-
# Add tool to parser
50-
tool_cls: InfuseCommand = module.SubCommand
51-
parser = tools_parser.add_parser(
52-
tool_cls.NAME,
53-
help=tool_cls.HELP,
54-
description=tool_cls.DESCRIPTION,
55-
formatter_class=argparse.RawDescriptionHelpFormatter,
56-
)
57-
parser.set_defaults(tool_class=tool_cls)
58-
tool_cls.add_parser(parser)
62+
self._load_from_module(tools_parser, module)
63+
64+
# Load custom tools, if configured
65+
if extension_tools := get_custom_tool_path():
66+
extension_path = pathlib.Path(extension_tools)
67+
for _, name, _ in pkgutil.walk_packages([extension_tools]):
68+
full_name = f"{infuse_iot.tools.__name__}.{name}"
69+
full_path = str(extension_path / f"{name}.py")
70+
spec = importlib.util.spec_from_file_location(full_name, full_path)
71+
if spec is None or spec.loader is None:
72+
continue
73+
module = importlib.util.module_from_spec(spec)
74+
try:
75+
spec.loader.exec_module(module)
76+
except Exception as _:
77+
continue
78+
if hasattr(module, "SubCommand"):
79+
self._load_from_module(tools_parser, module)
5980

6081

6182
def main(argv=None):

0 commit comments

Comments
 (0)