Features¶
Command Plugin¶
To add existing plugins to the base plugin:
configure plugin json file
Each { } in modules is a plugin to be added. Schema for the valid plugin json file:
{ "modules" : [ { "name" : <name of plugin shown in command line>, "click_root" : <the root command / group in cli.py>, "package_path" : <relative path to plugin folder based on cli file>, "package_name" : <plugin_folder_name>.<cli.py> } ] }
Please check the example on getting start for real usage.
Add the decorator, loadPlugin, to the base plugin in the cli.py based on plugin json file
from metacli.decorators import loadPlugin @loadPlugin(json_file="plugin_commands.json", base_path=__file__) @click.group() def base_plugin(): pass
- Parameters:
json_file: the plugin JSON file’s name
base_path: current cli file path
Supported Plugin
Now we can support command line project based on Click. Here are some open-sourced Click project on Github:
mycli : https://www.mycli.net/
pgcli : https://www.pgcli.com/
example: Getting Start
Dependency Management¶
Once some plugins are added into base plugin, the package dependency or conflicts need to be solved. So, before starting to run this project, the dependency management need to be used firstly.
- Run dependency management in the console as a command line to generate requirements.txt:
metacli dependency_managementNote: enter the absolute path to the base plugin folder
- Check package conflicts
Check the console for messages about “Found a package of different versions in requirements.txt.”
Go through the requirements.txt and pick the version that best fits your plugin
Install the packages :
pip install -r requirements.txtIf you choose to not resolve the package conflicts and want to install the first appeared version of the conflict packages, try:
cat requirements.txt | xargs -n 1 pip install
Built-in Plugin¶
MetaCLI support some built-in plugin. These commands can be added using decorator:
from metacli.decorators import addBuiltin
@addBuiltin(name="schema")
@addBuiltin(name="shell")
@click.group()
def base_plugin():
pass
shell prompt¶
MetaCLI shell support running all commands in interactive prompt, also support save and retrieve parameters in different command layers.
To use it, use “shell” as command:
<plugin_name> shell
Features:
Logs all the commands run in the shell in generated file shell_history
Saves all parameter values in hidden file and allow other commands to read the latest saved parameters in shell
- Built in Commands:
<plugin_name> > :qUse :q or :quit to quit the shell
<plugin_name> > :helpUse :help or :h to show all the available commmands and saved options for a group
<plugin_name> > :shell_historyOption “—debug”: to show all saved parentheses for all group level sessions.
Use :shell_history or :sh to show all saved parameter values for current group level session and previous group level sessions
Use :set or :s to set a value for a specify parameter
schema description¶
When a lot of plugins are added into base, it maybe hard for user to know the entire structure for this command. so Metacli provide the schema describing plugin.
To use it, add the “schema” plugin into code, and run thE command:
<plugin_name> schema --display
- Tips:
–display is an optional argument, is this one is added, the structure will be shown in console
“schema.json” will be generated in current folder.This file describe the commands, arguments and etcs.
Project Generator¶
MetaCLI can help to generate a new project easily.
Simple Project¶
To create an simple command line project, run this command in terminal:
$ metacli create_project # (optional) --inlcude_template True
To use default path and name (current path and helloworld), just press Enter in prompt. Also you can input the path and the name for this new project. Then a new project is generated. In this new project, here is the file structure.
- project core files
setup.py: the file which can install the project to system
<name>cli.py: the file which contains all command
__init__.py: indicate this project as Python package, the version can be defined here
- project plugin files:
plugin_commands.json: plugin configuration file
- template files (only appear if using –include_template True):
schema.json: this is a template schema file written in JSON.
schema.yaml: this file is same as schema.json, the only difference is it is written in yaml
This project can be run directly as a hello world command:
# in new project's folder
$ pip install --editable .
$ helloworld --help
Complex Project from templates¶
In the above session, we have 2 template schema files, MetalCLI can generate a complex project based on schema file easily.
Here we take the JSON format as an example, the YAML file is similar
Three different data structures in click are supported now in our generator: Group, Command and Option
We list the required fields for each structure:
- group:
name: String, define the name for this group
help: String, help information for this group
hidden: Boolean String [“True”, “False”], whether this group is hidden or not
groups: List, subgroups under this group
commands: List, commands under this group
params: List, parameters for this group
- command:
name: String, define the name for this command
help: String, help information for this command
hidden: Boolean String [“True”, “False”], whether this command is hidden or not
params: List, parameters for this command
- parameters:
name: String, parameter name
help: String, help information for this parameter
type: String [“BOOL”, “STRING”], define the data type for this parameter
default: String: default value for this argument, must satisfy the data type you defined
required: Boolean String [“True”, “False”], whether this is a required parameter or not
prompt: Boolean String [“True”, “False”], define the input method for this parameter
param_type: “option” (only support option right now)
The sample template is provided when the argument –include_template is true. A new project can be generated based on this sample schema directly:
$ metacli create_project --fromjson '<path for template JSON file>'
Then, a new project is generated.
The YAML file is similar, the only difference here is:
$ metacli create_project --fromyaml '<path for template YAML file>'
To use this sample project:
$ <project name> example_command --example_argument <test parameter>
$ this is group example_group
$ parameters:
$ this is command example_command
$ parameters: <test parameter>
Logging¶
MetaCLI support a simple logging system, this feature can be used as following:
Catch all exceptions into user specified log file in base plugin using decorator loadLogging
- Summarize all logs into user specified log file in base plugin
Use get_logger to specify log file and get the logger
Save logger as part of context for base plugin using set_context_obj
from metacli.decorators import loadLogging from metacli.util import get_logger, set_context_obj @loadLogging(logger_name=<specified_log_file>) @click.group() def base_plugin(ctx): if ctx.obj: return logger = get_logger(<specified_log_file>) my_ctx_obj = { "logger": logger } set_context_obj(ctx, my_ctx_obj)
- set_context_obj sets the context object that allows user to add atributes to context
- Parameters:
ctx : context for the plugin
my_ctx_obj : optional user defined dictionary of attributes for context
- Allow logging with different contexts for plugins at different levels
- Child plugins can add attributes to the context of parent plugin
Create my_ctx_obj to specify new attributes for context
Call set_context_obj with both parameters ctx and my_ctx_obj
- Can specify different log files for plugins at different levels or use same logger
- To use different log file for a plugin:
Call get_logger to get different log file and logger
Create my_ctx_obj with new logger
Call
set_context_obj(ctx, my_ctx_obj)To use the same log file, then directly call
set_context_obj(ctx)