-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change CLI backend to typer #76
Comments
@abhijeetSaroha if you create a script with this code (for example, testtyper.py), you can test it locally using this: $ python testtyper.py --help |
this example still need changes in order to recognize well the args for each target |
this is an example how to have it working also with the args: import typer
import click
app = typer.Typer()
# Example targets dictionary
targets = {
"clean.all": {
"help": "clean all temporary files"
},
"tests.unit": {
"help": "unit tests",
"args": {
"testname": {
"type": "str",
"default": "tests",
"help": "set the file name of the test file."
}
}
},
"tests.linter": {
"help": "run linter",
},
}
def type_mapper(type_name):
"""
Maps a string representation of a type to the actual Python type.
Parameters
----------
type_name : str
The string representation of the type.
Returns
-------
type
The corresponding Python type.
"""
type_mapping = {
'str': str,
'int': int,
'float': float,
'bool': bool
# Add more mappings as needed
}
return type_mapping.get(type_name, str)
def apply_click_options(command_function, options):
"""
Apply Click options to a Typer command function.
Parameters
----------
command_function : callable
The Typer command function to which options will be applied.
options : dict
A dictionary of options to apply.
Returns
-------
callable
The command function with options applied.
"""
for opt_name, opt_details in options.items():
click_option = click.option(
f'--{opt_name}',
default=opt_details.get('default'),
type=type_mapper(opt_details.get('type', 'str')),
help=opt_details.get('help', '')
)
print()
command_function = click_option(command_function)
return command_function
def create_dynamic_command(name, args):
"""
Dynamically create a Typer command with the specified options.
Parameters
----------
name : str
The command name.
args : dict
The command arguments and options.
"""
args_str = "" if not args.get('args', {}) else ",".join([
f"{name}: {spec['type']}" + ('' if not spec.get('default') else f'= \"{spec["default"]}\"')
for name, spec in args.get('args', {}).items()
])
decorator = app.command(
name=name,
help=args['help']
)
function_code = (
f"def dynamic_command({args_str}):\n"
" typer.echo(f'Executing ' + name)\n"
"\n"
)
local_vars = {}
exec(function_code, globals(), local_vars)
dynamic_command = decorator(local_vars["dynamic_command"])
# Apply Click options to the Typer command
if 'args' in args:
dynamic_command = apply_click_options(dynamic_command, args['args'])
return dynamic_command
# Add dynamically created commands to Typer app
for name, args in targets.items():
create_dynamic_command(name, args)
if __name__ == "__main__":
app() it is a very dirty example, for example for default it is just working for strings, but it should work for other types as well |
def create_args_string(args):
args_rendered = []
for name, spec in args.get('args', {}).items():
arg_str = f"{name}: {spec['type']}"
if not spec.get('default'):
args_rendered.append(arg_str)
continue
if spec['type'] == "str":
arg_str += f'= \"{spec["default"]}\"'
else:
arg_str += f'= {spec["default"]}'
args_rendered.append(arg_str)
return "".join(args_rendered) |
resolved by #82 |
initial idea about how it could be implemented:
this is not the final version of the code, instead it is an example that shows that it would be possible
The text was updated successfully, but these errors were encountered: