Skip to content

Commit ae2c182

Browse files
authored
Merge pull request #25 from oleks-dev/split_engine
refactor engine.py, split into smaller files
2 parents 8a0d7b2 + 8ae7c52 commit ae2c182

20 files changed

+463
-387
lines changed

prich/cli/dynamic_command_group.py

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import click
2+
from prich.constants import RESERVED_RUN_TEMPLATE_CLI_OPTIONS
3+
from prich.models.template import TemplateModel
24
from prich.core.loaders import load_global_config, load_local_config, load_merged_config, load_templates
3-
from prich.core.engine import create_dynamic_command
5+
from prich.core.engine import run_template
46
from prich.core.state import _loaded_templates
5-
from prich.core.utils import should_use_global_only, should_use_local_only
7+
from prich.core.utils import should_use_global_only, should_use_local_only, is_verbose, console_print
68

79

810
class DynamicCommandGroup(click.Group):
@@ -31,4 +33,66 @@ def _load_dynamic_commands(self, ctx):
3133
except Exception as e:
3234
raise click.ClickException(f"Failed to load dynamic parameters: {e}")
3335

34-
self._commands_loaded = True
36+
self._commands_loaded = True
37+
38+
39+
def get_variable_type(variable_type: str) -> click.types:
40+
type_mapping = {"str": click.STRING, "int": click.INT, "bool": click.BOOL, "path": click.Path}
41+
return type_mapping.get(variable_type.lower(), None)
42+
43+
44+
def create_dynamic_command(config, template: TemplateModel) -> click.Command:
45+
options = []
46+
for arg in template.variables if template.variables else []:
47+
arg_name = arg.name
48+
arg_type = get_variable_type(arg.type)
49+
help_text = arg.description or f"{arg_name} option"
50+
cli_option = arg.cli_option or f"--{arg_name}"
51+
if cli_option in RESERVED_RUN_TEMPLATE_CLI_OPTIONS:
52+
raise click.ClickException(f"{arg_name} cli option uses a reserved option name: {cli_option}")
53+
54+
if arg_type == click.BOOL:
55+
options.append(click.Option([cli_option], is_flag=True, default=arg.default or False, show_default=True,
56+
help=help_text))
57+
elif arg_type:
58+
options.append(
59+
click.Option([cli_option], type=arg_type, default=arg.default, required=arg.required, show_default=True,
60+
help=help_text))
61+
elif arg.type.startswith("list["):
62+
list_type = get_variable_type(arg.type.split('[')[1][:-1])
63+
if not list_type:
64+
raise click.ClickException(f"Failed to parse list type for {arg.name}")
65+
options.append(
66+
click.Option([cli_option], type=list_type, multiple=True, default=arg.default, required=arg.required,
67+
show_default=True, help=help_text))
68+
else:
69+
raise click.ClickException(f"Unsupported variable type: {arg.type}")
70+
71+
options.extend([
72+
click.Option(["-g", "--global", "global_only"], is_flag=True, default=False,
73+
help="Use global config and template"),
74+
click.Option(["-l", "--local", "local_only"], is_flag=True, default=False,
75+
help="Use local config and template"),
76+
click.Option(["-o", "--output"], type=click.Path(), default=None, show_default=True,
77+
help="Save final output to file"),
78+
click.Option(["-p", "--provider"], type=click.Choice(config.providers.keys()), show_default=True,
79+
help="Override LLM provider"),
80+
click.Option(["-v", "--verbose"], is_flag=True, default=False, help="Verbose mode"),
81+
click.Option(["-q", "--quiet"], is_flag=True, default=False, help="Suppress all output"),
82+
click.Option(["-f", "--only-final-output"], is_flag=True, default=False,
83+
help="Suppress output and show only the last step output")
84+
])
85+
86+
@click.pass_context
87+
def dynamic_command(ctx, **kwargs):
88+
if is_verbose():
89+
console_print(
90+
f"[dim]Template: [green]{template.name}[/green] ({template.version}), {template.source.value}, args: {', '.join([f'{k}={v}' for k, v in kwargs.items() if v])}[/dim]")
91+
console_print(f"[dim]{template.description}[/dim]")
92+
else:
93+
console_print(f"[dim][green]{template.name}[/green] ({template.version}), {template.source.value}[/dim]")
94+
run_template(template.id, **kwargs)
95+
96+
return click.Command(name=template.id, callback=dynamic_command, params=options,
97+
help=f"{template.description if template.description else ''}",
98+
epilog=f"{template.name} (ver: {template.version}, {template.source.value})")

prich/cli/init_cmd.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import subprocess
55
import venv
66
import click
7+
from prich.constants import PRICH_DIR_NAME
78
from prich.core.utils import console_print, get_prich_dir
89
from prich.models.config_providers import EchoProviderModel
910
from prich.models.config import SettingsConfig, ConfigModel, ProviderModeModel
1011

1112

1213
@click.command()
13-
@click.option("-g", "--global", "global_init", is_flag=True, help="Initialize ~/.prich/ (global)")
14+
@click.option("-g", "--global", "global_init", is_flag=True, help=f"Initialize ~/{PRICH_DIR_NAME}/ (global)")
1415
@click.option("--force", is_flag=True, help="Overwrite existing config")
1516
def init(global_init: bool, force: bool):
1617
"""Initialize prich configuration and default venv."""
@@ -24,10 +25,10 @@ def init(global_init: bool, force: bool):
2425
default_venv = prich_dir / "venv"
2526
if force:
2627
# for safety, ensure that we remove only related folder
27-
if ".prich" in str(default_venv):
28+
if PRICH_DIR_NAME in str(default_venv):
2829
shutil.rmtree(default_venv, ignore_errors=True)
2930
else:
30-
raise click.ClickException(".prich folder is not part of venv folder path")
31+
raise click.ClickException(f"{PRICH_DIR_NAME} folder is not part of venv folder path")
3132
if not default_venv.exists():
3233
builder = venv.EnvBuilder(with_pip=True)
3334
builder.create(default_venv)
@@ -49,7 +50,8 @@ def init(global_init: bool, force: bool):
4950
},
5051
provider_modes=[
5152
ProviderModeModel(name="plain", prompt="{% if instructions %}{{ instructions }}\n{% endif %}{{ input }}"),
52-
ProviderModeModel(name="flat", prompt="""{% if instructions %}### System:\n{{ instructions }}\n\n{% endif %}### User:\n{{ input }}\n\n### Assistant:"""),
53+
ProviderModeModel(name="flat",
54+
prompt="{% if instructions %}### System:\n{{ instructions }}\n\n{% endif %}### User:\n{{ input }}\n\n### Assistant:"),
5355
# ProviderModeModel(name="mistral-instruct", prompt="""<s>[INST]\n{% if instructions %}{{ instructions }}\n\n{% endif %}{{ input }}\n[/INST]"""),
5456
# ProviderModeModel(name="llama2-chat", prompt="""<s>[INST]\n{% if instructions %}{{ instructions }}\n\n{% endif %}{{ input }}\n[/INST]"""),
5557
# ProviderModeModel(name="anthropic", prompt="""Human: {% if instructions %}{{ instructions }}\n\n{% endif %}{{ input }}\n\nAssistant:"""),

prich/cli/templates.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pathlib import Path
88
import click
99

10+
from prich.constants import PRICH_DIR_NAME
1011
from prich.core.loaders import get_loaded_templates, get_loaded_config, get_loaded_template
1112
from prich.core.utils import console_print, is_valid_template_id, get_prich_dir, get_prich_templates_dir, shorten_path
1213
from prich.cli.venv_utils import install_template_python_dependencies
@@ -63,7 +64,7 @@ def check_if_dest_present(template_id: str, dest_folder: Path, global_install: b
6364
@click.argument("path")
6465
@click.option("--force", is_flag=True, help="Overwrite existing templates")
6566
@click.option("--no-venv", is_flag=True, help="Skip venv setup")
66-
@click.option("-g", "--global", "global_install", is_flag=True, help="Install to ~/.prich/templates")
67+
@click.option("-g", "--global", "global_install", is_flag=True, help=f"Install to ~/{PRICH_DIR_NAME}/templates")
6768
@click.option("-r", "--remote", "from_remote", is_flag=True, help="Install template from prich-templates GitHub repo or zip URL")
6869
def template_install(path: str, force: bool, no_venv: bool, global_install: bool, from_remote: bool):
6970
"""Install a template from PATH, zip, or prich-templates."""

prich/cli/validate.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
from pathlib import Path
33
import click
4+
from prich.constants import PRICH_DIR_NAME
45
from prich.models.template import CommandStep, PythonStep
56
from prich.core.file_scope import classify_path
67
from prich.core.loaders import find_template_files, load_template_model, get_env_vars
@@ -19,7 +20,7 @@ def validate_templates(template_id: str, validate_file: Path, global_only: bool,
1920
raise click.ClickException("Use only one local or global option, use: 'prich validate -g' or 'prich validate -l'")
2021

2122
if validate_file and (global_only or local_only or template_id):
22-
raise click.ClickException("When YAML file is selected it doesn't combine with local, global, or id options, use: 'prich validate --file ./.prich/templates/test-template/test-template.yaml'")
23+
raise click.ClickException(f"When YAML file is selected it doesn't combine with local, global, or id options, use: 'prich validate --file ./{PRICH_DIR_NAME}/templates/test-template/test-template.yaml'")
2324

2425
if validate_file and not validate_file.exists():
2526
raise click.ClickException(f"Failed to find {validate_file} template file.")

prich/cli/venv_utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55

66
import click
77

8+
from prich.constants import PRICH_DIR_NAME
89
from prich.core.utils import shorten_path, console_print
910

1011

1112
def install_python_venv(venv_folder: Path, force: bool = False, venv_type: str = ""):
1213
if venv_folder.exists() and force:
13-
if ".prich" in str(venv_folder):
14+
if PRICH_DIR_NAME in str(venv_folder):
1415
console_print(f"Removing existing {venv_type} venv folder...", end="")
1516
shutil.rmtree(venv_folder)
1617
else:
17-
raise click.ClickException(".prich folder is not part of venv folder path")
18+
raise click.ClickException(f"{PRICH_DIR_NAME} folder is not part of venv folder path")
1819
console_print(" [green]done![/green]")
1920
elif venv_folder.exists():
2021
console_print("Venv folder found.")

prich/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
"-g", "--global", "-q", "--quiet", "-o", "--output", "-p", "--provider",
55
"-f", "--only-final-output", "-v", "--verbose"
66
]
7+
8+
# .prich folder name
9+
PRICH_DIR_NAME = ".prich"

0 commit comments

Comments
 (0)