Package: verb
verbEasy make mini-languages to do python things.To install:pip install verbDo things like this:fromverbimportmk_executerfunc_of_key={'plus':lambdax,y:x+y,'minus':lambdax,y:x-y,}execute=mk_executer(func_of_key)execute('3 minus 2 plus 1')## 2execute('9 minus 6')## 3A quick intro to CommandUses cases: In situations where you want to get some input from a user (from the web,
in a command line, etc.) that specifies a computation to be carried out, you know
(right) that you definitely shouldn't resort to usingevalorexec.
Because it's dangerous for everyone involved -- let's just not go there.verboffers an alternative: Easily building minilanguages that will allow the user
to only execute the functions you choose, through a vocabulary you choose,
and everyone can go home (as) safe (as you allow).In a nutshell, you make a key-to-func mapping (or use the default).
Thisfunc_of_keymapping is what specifies yourinterpreter:fromverbimport*importoperatorasofunc_of_key={# Note: Order represents precedence!'-':o.sub,'+':o.add,'*':o.mul,'/':o.truediv,}Now you have a minilanguage! Out-of-the-box it will allow you to "speak it in string"
or "speak it in json/dict", but you can extend to enable the language to be written in
any container you want.If you give it a "command string":command_str='1 + 2 - 3 * 4 / 8'command=Command(command_str,func_of_key)command_str = '1 + 2 - 3 * 4 / 8'
command = Command(command_str, func_of_key)It will usefunc_of_keyto both parse it and replace the keys with an indication
that the corresponding function should be called.commandis a callable object, and when you call it,
it executes it's instructions:command()1.5It may be useful to see what the operation structure looks liked=command.to_dict()d{'-': ({'+': (1, 2)}, {'*': (3, {'/': (4, 8)})})}# Or if you read better with indentsfromfunctoolsimportpartialimportjsonfromlinedimportPipeprint_jdict=Pipe(partial(json.dumps,indent=2),print)# Note: Only works if your dict is JSON-izable.print_jdict(d){
  "-": [
    {
      "+": [
        1,
        2
      ]
    },
    {
      "*": [
        3,
        {
          "/": [
            4,
            8
          ]
        }
      ]
    }
  ]
}That same dict can be used as a parameter to make the same commandcommand=Command(d,func_of_key)command()1.5Example: Table Selector Mini LanguageimportoperatorasofromtypingimportCallable,MappingfromfunctoolsimportpartialimportpandasaspdfromlinedimportPipefromverbimportstr_to_basic_pyobj,Commanddflt_func_of_key_for_table_selection={# Note: Order represents precedence!'&':o.__and__,'==':o.__eq__,'<=':o.__le__,'>=':o.__ge__,'<':o.__lt__,'>':o.__gt__,}defmk_table_selector(table:pd.DataFrame,func_of_key:Mapping[str,Callable]=dflt_func_of_key_for_table_selection):defleaf_processor(x):x=str_to_basic_pyobj(x)ifxintable:returntable[x]returnxrun_command=Pipe(partial(Command.from_string,func_of_key=func_of_key,leaf_processor=leaf_processor),lambdaf:f(),lambdaidx:table[idx],)returnrun_commandimportpandasaspddf=pd.DataFrame([{'source':'audio','bt':5,'tt':7,'annot':'cat'},{'source':'audio','bt':6,'tt':9,'annot':'dog','comments':'barks and chases cat away'},{'source':'visual','bt':5,'tt':8,'annot':'cat'},{'source':'visual','bt':6,'tt':15,'annot':'dog','comments':'dog remains in view after bark ceases'}])dfsourcebtttannotcomments0audio57catNaN1audio69dogbarks and chases cat away2visual58catNaN3visual615dogdog remains in view after bark ceasesrun_command=mk_table_selector(df)run_command('source == audio')sourcebtttannotcomments0audio57catNaN1audio69dogbarks and chases cat awayrun_command('tt <= 8')sourcebtttannotcomments0audio57catNaN2visual58catNaNrun_command('source == audio & tt <= 8')sourcebtttannotcomments0audio57catNaN