... or how to integrate groups of tasks with similar options.
This section will present a more complex use case where we have three commands: bigdog, catkiller and eagle which purpose is to find cats.
We will start by integrating bigdog to secator before realizing that most options can be mutualized between the three tools, and a common output type Cat can be created for all three.
Bigdog
Let's suppose we have a fictional utility called bigdog which purpose is to hunt cats on the internet. We want to add bigdog to secator.
You can now run bigdog from the CLI or the library:
secatorxbigdog--helpsecatorxbigdogloadsofcats.com
from secator.tasks import bigdog# Get all results as a list, blocks until command has finished runningbigdog('loadsofcats.com').run()[{"name":"garfield","age":14,"host":"loadofcats.com","position":"boss"},{"name":"tony","age":18,"host":"loadsofcats.com","position":"admin"}]# Get result items in real-time as they arrive to stdoutfor cat inbigdog('loadsofcats.com'):print(cat['name'] +'('+ cat['age'] +')')# Will printgarfield (14)tony (18)
Okay, this is a good start.
Now what if the bigdog command has some more options that you would like to integrate ?
-timeout allows to specify a request timeout.
-rate allows to specify the max requests per minute.
You can add the opts parameter to your Command object to define the cmd options:
from secator.runners import Commandfrom secator.decorators import task@taskclassbigdog(Command): cmd ='bigdog' json_flag ='-json' input_flag ='-site' file_flag ='-list' opt_prefix ='-' opts ={'timeout':{'type':int,'help':'Timeout (in seconds)'},'rate':{'type':int,'help':'Max requests per minute'}}
from secator.tasks import bigdogbigdog('loadsofcats.com', rate=100, timeout=3).run()# adding rate and timeout options
Cat hunters category
One advantage of having class-based definitions is that we can group similar tools together in categories.
Let's assume we have 2 other tools that can hunt cats: catkiller and eagle...
... but each of those tools might be written by a different person, and so the interface and output is different for each of them:
$catkiller--hostloadsofcats.com--max-wait1000--max-rate10--jsonStartingcatkillersession...{"_info":{"name":"tony","years":18},"site":"loadsofcats.com","job":"admin"}{"_info":{"name":"garfield","years":14},"site":"loadsofcats.com","job":"boss"}# or to pass multiple hosts, it needs to be called like:$cathosts.txt|catkiller--max-wait1000--max-rate10--json
Inputs:
--host is equivalent to bigdog's -site.
--max-wait is equivalent to bigdog's -timeout, but in milliseconds instead of seconds.
--max-rate is equivalent to bigdog's -rate.
--json is equivalent to bigdog's-json option, but uses a different option character "--".
cat hosts.txt | catkiller is the equivalent tobigdog's -list.
Output:
_info has the data for name and age, but age is now years.
site is the equivalent of bigdog's host.
job is the equivalent of bigdog's position.
$eagle-uloadsofcats.com-timeexpires1-jsonl_||_________||___/_ \/ _` |/_`||/_ \|__/ (_|| (_|||__/v2.2.0\___|\__,_|\__,|_|\___|__/||___/{"alias":"tony","occupation":"admin","human_age":105}# or to pass multiple hosts, it needs to be called like:$eagle-lhosts.txt-timeexpires1-jsonl_||_________||___/_ \/ _` |/_`||/_ \|__/ (_|| (_|||__/v2.2.0\___|\__,_|\__,|_|\___|__/||___/{"alias":"tony","occupation":"admin","human_age":105,"host":"loadsofcats.com"}
Inputs:
-u is equivalent to bigdog's -site.
-l is equivalent to bigdog's -list.
-timeexpires is equivalent to bigdog's -timeout.
eagledoes not support setting the maximum requests per seconds (bigdog's -rate).
-jsonl is the flag to output JSON lines, instead of bigdog's -json.
Output:
alias is the equivalent of bigdog's name.
occupation is the equivalent of bigdog's job.
human_age is the human age conversion of the cat age.
Cat output type
We first define a base Cat dataclass to define the common output schema and a CatHunter category as an input interface.
We take bigdog's output schema as reference to create the Cat output type:
We take bigdog's options names as reference and add the ones that can be mutualized to the CatHunter category:
secator/tasks/_categories.py
from secator.output_types import Cat# ...classCatHunter(Command): meta_opts ={'timeout':{'type':int,'default':1,'help':'Timeout (in seconds)'},'rate':{'type':int,'default':1000,'help':'Max requests per minute'},} output_types = [Cat]
Tools implementation
Finally we inherit all commands implementation from CatHunter and write the option mapping for the remaining cat-hunter commands: