Overview
| module url | https://pypi.org/project/py-runner-base.html | ||||||||||
| git repository | https://bitbucket.org/arrizza-public/py-runner-base | ||||||||||
| git command | git clone git@bitbucket.org:arrizza-public/py-runner-base.git | ||||||||||
| verification report | https://arrizza.com/web-ver/py-runner-base-report.html | ||||||||||
| version info |
|
- repo status: Repo Information
- installation: Common Setup
Summary
This project is a base class for running various commands in python from the command line.
see sample/toolbox_app.py for an example use.
see doc/api.md for the API available.
how to run
Don't specify a command gives you help. Note that you can use check() in toolbox_runner.py or run() in toolbox_app.py to specify a default command.
./doit
WARN no command chosen, nothing to do
py-runner-base: v0.1.0
Choose one of these:
task1 : run task1
task2a : run task2 step-a
task2b : run task2 step-b
task3 : run task3
task4 : run task4
Note: that there are several sorting orders available, see property sort_order in base_runner.py or
cmd_map.py.
- Add an argument
arg1:
$ ./doit task1 arg1
==== doit: starting...
running Task1 args:['arg1']
doit: run_it rc=0
- Run a command "task1" that has no prerequisites:
./doit task1
==== doit: starting...
running Task1 args:[]
doit: run_it rc=0
- Run a command "task2b" that has a prerequisite:
./doit task2b
==== doit: starting...
running Task2 step-a
running Task2 step-b
doit: run_it rc=0
how to add commands
See the sample/taskxx.py files for example tasks.
Note register() functions that allow you to specify command names for any tasks
you want to add.
# --------------------
def register(self, runner):
self._runner = runner
self._runner.add_cmd('task2a', self._run_step_a, 'run task2 step-a')
self._runner.add_cmd('task2b', self._run_step_b, 'run task2 step-b', prereqs=['task2a'])
API
Typically three classes are needed:
- xx_app.py: hold all the references, do all the setup and configuration, and then run the commands.
- xx_runner.py: derives from
RunnerBaseand handles any special command setup, argument handling, etc. - xx_taskx.py : one or more classes to hold the code that implements the command(s)
xx_app.py
Typical:
# import task class(es) here
class ToolboxApp:
def __init__(self):
# any initialization here
# create an instance of parent of RunnerBase
self._runner = ToolboxRunner()
# build toolbox from the base and the mixins wanted
tasks = (
Task1, # _ do Task1
Task2, # _ do Task2
)
# register() all the tasks.
# register() can take a tuple, a list, or an individual class
# Each tasks is class name, the register() instantiates it.
self._runner.register(tasks)
self._runner.register([Task3])
self._runner.register(Task4)
# the main.py invokes this function
def run(self):
# parse the CLI commands the user typed in
self._runner.get_cli_info()
# if there's any problems return
if self._runner.rc != 0:
return
# do a double-check. Your version may or may not need this.
self._runner.check()
if self._runner.rc != 0:
return
# all is well, so run any/all the commands specified by the user
# note that you can specify that only one command be called, or N, whatever is needed
self._runner.run_all()
# note that main.py will use svc.rc to ensure sys.exit() returns with the right rc.
svc.rc += self._runner.rc
xx_taskx.py
A typical class to register and run a command:
class Task1:
def __init__(self):
# needed to access any CLI args (or can use sys.argv[])
self._runner = None
def register(self, runner):
# save the runner parent instance
self._runner = runner
# register a command "task1", the function to run and some help text
self._runner.add_cmd('task1', self._run, 'run task1')
def _run(self):
# the command to run when task1 is declared
# must return an rc so the sys.exit() can be set correctly
errs = 0
svc.log.line(f'running Task1 args:{self._runner.args}')
return errs
xx_runner.py
The runner parent class:
from src.py_runner_base.runner_base import RunnerBase
# other imports as needed
class ToolboxRunner(RunnerBase):
def __init__(self):
super().__init__()
# initialize the base runner and share the same logger
self.init_runner_base(svc.log)
def handle_unknown_arg(self, arg):
# not a recognized command/task/step so assume it is an arg
self._args.append(arg)
return True
def check(self):
if self.nothing_chosen():
svc.rc += 1
svc.log.warn('no command chosen, nothing to do')
self.report_err_msg()
API
init_runner_base
- initialize the base content
- logger: set the logger
- prefix: set the prefix to use for any logging
sort_order (property and setter)
- set the order that the commands are executed
- created - (default) run as created via calls to register()
- entered - run as entered
- alpha - sort alphabetically
- index - sort by index
add_cmd
- called by task classes to register a command
- cmd - the command name
- cmd_fn - the function to invoke when this command is named
- desc - help for this command
- prereqs - any pre-requisite commands for this cmd
- sort_idx - the sorting value/index for this cmd (see sort_order)
run_all
- run all of the commands requested by the CLI. The commands are sorted according to the sort_order()
- see run_cmd() for individual commands.
run_cmd
- run the given command. Typically run via run_all().
- cmd_name - the cmd name
- returns an integer rc
rc
- returns the current return code. Note the return code is a sum of all values returned by the invoked command functions
get_cli_info
- get commands and args from the command line
handle_unknown_arg
- callback when an unknown CLI arg is found by get_cli_info().
Normally this is overridden when using this base class
- _arg - the CLI argument found
- should return True if no error occurred, False when an error occurred
report_err_msg
- reports the list of registered commands
nothing_chosen
- returns True if the cmd list from the CLI is empty, False otherwise
cmds
- returns the current set of commands that will be run
args
- returns any CLI args entered
- Note: "-n" is predefined. This causes run_cmd() to only write a log line to stdout.
dry_run
- returns True if this a dry run. see "-n" CLI arg.
delete_cmd
- delete the given command from the list of commands to run
- cmd_name - the cmd to remove