diff --git a/ofx_processor/bpvf_processor/bpvf_cli.py b/ofx_processor/bpvf_processor/bpvf_cli.py index ca1eb84..a59be14 100644 --- a/ofx_processor/bpvf_processor/bpvf_cli.py +++ b/ofx_processor/bpvf_processor/bpvf_cli.py @@ -3,7 +3,7 @@ import click from ofx_processor.bpvf_processor.bpvf_processor import BpvfProcessor -@click.command(help="Process BPVF bank statement (OFX)") +@click.command("bpvf", help="Process BPVF bank statement (OFX)") @click.argument("ofx_filename") def main(ofx_filename): BpvfProcessor(ofx_filename).push_to_ynab() diff --git a/ofx_processor/ce_processor/ce_cli.py b/ofx_processor/ce_processor/ce_cli.py index 0a024b2..aeae3a2 100644 --- a/ofx_processor/ce_processor/ce_cli.py +++ b/ofx_processor/ce_processor/ce_cli.py @@ -3,7 +3,7 @@ import click from ofx_processor.ce_processor.ce_processor import CeProcessor -@click.command(help="Process CE bank statement (OFX)") +@click.command("ce", help="Process CE bank statement (OFX)") @click.argument("ofx_filename") def main(ofx_filename): CeProcessor(ofx_filename).push_to_ynab() diff --git a/ofx_processor/main.py b/ofx_processor/main.py index c949ddb..b11d43b 100644 --- a/ofx_processor/main.py +++ b/ofx_processor/main.py @@ -1,9 +1,7 @@ import click -from ofx_processor.bpvf_processor import bpvf_cli -from ofx_processor.ce_processor import ce_cli -from ofx_processor.revolut_processor import revolut_cli from ofx_processor.utils import ynab +from ofx_processor.utils.utils import discover_processors CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) @@ -14,10 +12,8 @@ def cli(): pass -cli.add_command(bpvf_cli.main, name="bpvf") -cli.add_command(revolut_cli.main, name="revolut") -cli.add_command(ce_cli.main, name="ce") cli.add_command(ynab.config, name="config") +discover_processors(cli) if __name__ == "__main__": cli() diff --git a/ofx_processor/revolut_processor/revolut_cli.py b/ofx_processor/revolut_processor/revolut_cli.py index 335da48..32e4753 100644 --- a/ofx_processor/revolut_processor/revolut_cli.py +++ b/ofx_processor/revolut_processor/revolut_cli.py @@ -3,7 +3,7 @@ import click from ofx_processor.revolut_processor.revolut_processor import RevolutProcessor -@click.command(help="Process Revolut bank statement (CSV)") +@click.command("revolut", help="Process Revolut bank statement (CSV)") @click.argument("csv_filename") def main(csv_filename): RevolutProcessor(csv_filename).push_to_ynab() diff --git a/ofx_processor/utils/utils.py b/ofx_processor/utils/utils.py new file mode 100644 index 0000000..5b23575 --- /dev/null +++ b/ofx_processor/utils/utils.py @@ -0,0 +1,36 @@ +import importlib +import pkgutil + +import click + +import ofx_processor + + +def discover_processors(cli: click.Group): + """ + Discover processors. To be discovered, CLIs need to match the following structure: + + ofx_processor + ├── __init__.py + └── _processor +    ├── __init__.py +    ├── _cli.py +    └── _processor.py + + Preferably, package_name and module_name are the same, but there is no restriction. + Finally, a "main" function will be looked for inside the _cli module. + This function must be a Click command with a unique name and will be added to the + main command line interface. + + :param cli: The main CLI to add discovered processors to. + """ + prefix = ofx_processor.__name__ + "." + for package in pkgutil.iter_modules(ofx_processor.__path__, prefix): + if package.name.endswith("_processor"): + module_prefix = package.name + "." + package = importlib.import_module(package.name) + for module in pkgutil.iter_modules(package.__path__, module_prefix): + if module.name.endswith("_cli"): + module = importlib.import_module(module.name) + if "main" in dir(module): + cli.add_command(module.main)