arguments

This module is meant to add all the support functions for arguments and inout parsing.

from fastcore.test import *

Find support function

optional_find let you search a string in forward or reverse order using one or more templates (aka: reference sub-strings).

It returns the first occurrence that is the leftmost in forward direction and rightmost in reverse direction. The occurrence returned is a tuple (position,template) where: + position: is the position inside the string. + template: is the copy of the template found. We need this to understand where that string finishes.


source

optional_find

 optional_find (x, cc, reverse=False)
# Single
test_eq( optional_find('abc','a')[0] , 0)
test_eq( optional_find('abc','c')[0] , 2)
test_eq( optional_find('abc','bc')[0] , 1)
test_eq( optional_find('abc','z'), None)
test_eq( optional_find('abcdefghiab','a',reverse=True)[0] , 9)
test_eq( optional_find('abc','bc',reverse=True)[0] , 1)

# Multi
test_eq( optional_find('abcdefghiab',['aa','fg','ia'],reverse=False)[0] , 5)
test_eq( optional_find('abcdefghiab',['aa','fg','ia'],reverse=True)[0] , 8)
test_eq( optional_find('abcdefghiab',['aa','ia','fg'],reverse=True)[0] , 8)

Character level utility


source

count_char

 count_char (x, c)
test_eq( count_char('abacda','a') , 3 )
test_eq( count_char('abacda','b') , 1 )
test_eq( count_char('abacda','z') , 0 )

source

count_delta

 count_delta (x, a='(', b=')')
test_eq(count_delta('asd(asd)'),0)
test_eq(count_delta('asd(asd'),1)
test_eq(count_delta('asd(a(sd'),2)
test_eq(count_delta('asd(a(sd)))'),-1)

String split utility

This is just a bit of syntactic sugar


source

split_and_strip

 split_and_strip (x, splitter)
test_eq(split_and_strip('a,b,c',','),['a','b','c'])
test_eq(split_and_strip(' a, b,c ',','),['a','b','c'])
test_eq(split_and_strip('',','),[])

Inout util

inout is the name of the portion of the complete arguments string that refers to input and output parameters.

For example in this magick line: %%testcell noglobals (aaa,bbb) ->(ccc) + raw_arguments: noglobals + inout: (aaa,bbb) ->(ccc)


source

process_inout

 process_inout (x, splitter='->')
test_eq(process_inout(None,splitter='->'),None)

test_eq(process_inout('(a,b,cc)->(d,ee)',splitter='->'),(['a','b','cc'],['d','ee']))
test_eq(process_inout(' (a,b,cc)  -> (d,ee) ',splitter='->'),(['a','b','cc'],['d','ee']))
test_eq(process_inout(' (a,b,cc)  -> () ',splitter='->'),(['a','b','cc'],[]))
test_eq(process_inout(' (a,b,cc)  ',splitter='->'),(['a','b','cc'],[]))
test_eq(process_inout('()->(a,b,cc)  ',splitter='->'),([],['a','b','cc']))
test_eq(process_inout('->(a,b,cc)  ',splitter='->'),([],['a','b','cc']))

test_fail(lambda: process_inout('(a,b,cc)(d,ee)'), contains='Too much parenthesis')
test_fail(lambda: process_inout('(a,b,cc) (d,ee)'), contains='Too much parenthesis')
test_fail(lambda: process_inout('(a,b,cc) (->d,ee)'), contains='Too much parenthesis')
test_fail(lambda: process_inout('(a,b,cc->)(d,ee)'), contains='Missing closing parenthesis')
test_fail(lambda: process_inout('(a,b,cc) - > (d,ee)'), contains='Too much parenthesis')
test_fail(lambda: process_inout('(a,b,cc) ? (d,ee)'), contains='Too much parenthesis')

source

separate_args_and_inout

 separate_args_and_inout (x)
test_eq(separate_args_and_inout(None), None)  # None input → None output

test_eq(separate_args_and_inout(''), ['', None])  # Empty string → empty args, no in/out
test_eq(separate_args_and_inout('verbose'), ['verbose', None])  # Only args, no in/out
test_eq(separate_args_and_inout('dryrun verbose'), ['dryrun verbose', None])  # Multiple args, no in/out
test_eq(separate_args_and_inout('(a,b)->(c,d)'), ['', '(a,b)->(c,d)'])  # Pure in/out spec, no args
test_eq(separate_args_and_inout('(a,b)'), ['', '(a,b)'])  # Only input tuple, no args
test_eq(separate_args_and_inout('->(c,d)'), ['', '->(c,d)'])  # Only output tuple, no args

test_eq(separate_args_and_inout('dryrun verbose (a,b)'), ['dryrun verbose ', '(a,b)'])  # Args + input tuple
test_eq(separate_args_and_inout('dryrun verbose (a,b) -> (c,d) '), ['dryrun verbose  ', '(a,b) -> (c,d)'])  # Args + in/out
test_eq(separate_args_and_inout('dryrun verbose  () -> (c,d) '), ['dryrun verbose   ', '() -> (c,d)'])  # Args + empty input tuple
test_eq(separate_args_and_inout('dryrun verbose (a,b) -> ()'), ['dryrun verbose ', '(a,b) -> ()'])  # Args + empty output tuple
test_eq(separate_args_and_inout('dryrun verbose (a,b)  '), ['dryrun verbose   ', '(a,b)'])  # Args + input tuple, trailing spaces

test_eq(separate_args_and_inout('dryrun  (a,b)  verbose '), ['dryrun    verbose ', '(a,b)'])  # In/out tuple between args
test_eq(separate_args_and_inout('dryrun  (a,b) -> (c,d) verbose'), ['dryrun   verbose', '(a,b) -> (c,d)'])  # In/out in middle of args
test_eq(separate_args_and_inout('dryrun () -> (c,d) verbose'), ['dryrun  verbose', '() -> (c,d)'])  # Empty input tuple
test_eq(separate_args_and_inout('dryrun () -> (c,d)verbose'), ['dryrun verbose', '() -> (c,d)'])  # No space before verbose
test_eq(separate_args_and_inout('dryrun() -> (c,d) verbose'), ['dryrun verbose', '() -> (c,d)'])  # No space before ()
test_eq(separate_args_and_inout('dryrun  (a,b)->() verbose'), ['dryrun   verbose', '(a,b)->()'])  # Compact arrow, spacing preserved
test_eq(separate_args_and_inout('dryrun (a, b)  verbose'), ['dryrun   verbose', '(a, b)'])  # Tuple spacing preserved

test_eq(separate_args_and_inout('dryrun -> (c,d)verbose'), ['dryrun verbose', '-> (c,d)'])  # Output tuple glued to arg
test_eq(separate_args_and_inout('dryrun (c,d)->verbose'), ['dryrun verbose', '(c,d)->'])  # Input tuple glued to arg

test_eq(separate_args_and_inout('dryrun (incomplete'), ['dryrun (incomplete', None])  # Unclosed parenthesis → ignore as in/out

Consume inout


source

validate_and_update_inputs

 validate_and_update_inputs (inputs:list, state:dict)
test_eq( validate_and_update_inputs(['a'],{'a':1, 'b':2}) , {'a':1} )
test_fail(lambda: validate_and_update_inputs(['a'],{'b':1}) , contains='not found: a' )
test_fail(lambda: validate_and_update_inputs(['a','c'],{'b':1}) , contains='not found: a, c' )