I have a Python script script1 that have multiple arguments which could be simplified as:
def add_vars(var1, var2, var3, var4, var5):
sum = var1+var2+var3+var4+var5
return sum
if __name__ == '__main__':
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description="""
simple addition
""")
parser.add_argument('var1', type=float, help='var1')
parser.add_argument('-var2', type=float, default=20, help='var2')
parser.add_argument('-var3', type=float, default=30, help='var3')
parser.add_argument('-var4', type=float, default=40, help='var4')
parser.add_argument('-var5', type=float, default=50, help='var5')
args = parser.parse_args()
print(args)
ss = add_vars(args.var1, args.var2, args.var3, args.var4, args.var5)
print('sum=', ss)
in which only arg1 is required and arg2-arg5 are optional.
I would like to call this script in another Python script with arg1, arg3 just like in the terminal:
script1.py 1 -var3 4
Does anyone know how to do this? I have tried os.execl but without luck.
EDIT: I'd say using subprocess wouldn't be a "better" way but this is a way you could do it?
from subprocess import check_output
out = check_output(["python", "script1.py", "1", "-var3", "4"])
print(out.decode("utf-8"))
Output:
Namespace(var1=1.0, var2=20, var3=4.0, var4=40, var5=50)
sum= 115.0
<empty line>
Original:
script1.py:
def add_vars(var1, var2=20, var3=30, var4=40, var5=50):
sum = var1+var2+var3+var4+var5
return sum
if __name__ == '__main__':
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
description="""simple addition""")
parser.add_argument('var1', type=float, help='var1')
parser.add_argument('-var2', type=float, default=20, help='var2')
parser.add_argument('-var3', type=float, default=30, help='var3')
parser.add_argument('-var4', type=float, default=40, help='var4')
parser.add_argument('-var5', type=float, default=50, help='var5')
args = parser.parse_args()
print(args)
ss = add_vars(args.var1, args.var2, args.var3, args.var4, args.var5)
print('sum=', ss)
script2.py:
import script1
print(script1.add_vars(1, var3=4))
var2=20, var3=30, var4=40, var5=50 sets the default values for the function (just like for argparse)
if __name__=='__main__'
resists your program functions to be called in other program
so you can do something like this in in other program
from script1.py import add_vars
and since you have given arg 1 and 3 default vals in the function you with other arguments so you have to be careful while passing other args , while you are in the other file
add_vars(arg1,arg3)
if you would have simply call script1.py then this would have not executed
if you have further question do add a comment i'll do make my best to answer your query
if you want to change vals of arg1 and arg3
add_vars(arg1=29,arg3=8)
you can specify them ,
so that their default value is overrided
Related
I need to integrate two files, one in python the other in julia. More precisely, I need to call a julia function, snapshot_sphere(b,h,data,m,r,d), from a python file. Moreover,I need to provide the parameters via the command line. I had difficulties in using PyJulia. For the moment an error message is persisting:
ModuleNotFoundError: No module named '_ctypes'
I found some dependencies related to libffi-dev. Installing it did not change anything. What should I do to call the julia function from the python file ?
Here is the code of the python file:
import argparse
from julia import Main
from PIL import Image, ImageShow
parser = argparse.ArgumentParser(description="Projection of the picture")
parser.add_argument(
"-f",
"--filename",
type=str,
action="store",
dest="fname",
help="Name of the picture"
)
parser.add_argument(
"-d",
"--density",
type=int,
action="store",
dest="density",
help="Number samples per Pixel"
)
parser.add_argument(
"-r",
"--radius",
type=float,
action="store",
dest="radius",
help="Radius of the sphere"
)
parser.add_argument(
"-x",
type=float,
action="store",
dest="x",
help="X coordinate of the center"
)
parser.add_argument(
"-y",
type=float,
action="store",
dest="y",
help="Y coordinate of the center"
)
parser.add_argument(
"-z",
type=float,
action="store",
dest="z",
help="Z coordinate of the center"
)
args = parser.parse_args()
print(args)
m = (args.x, args.y, args.z)
print(m)
im = Image.open(args.fname)
b, h = im.size
data = list(im.getdata())
Main.b = b
Main.h = h
Main.m = m
Main.r = args.radius
Main.d = args.density
Main.data = data
Main.include("projekt1.jl")
result = Main.eval("snapshot_sphere(b,h,data,m,r,d)")
Given an argument parser with n arguments, where I change the default value of only a small subset every run from the command line, is there a clean way of extracting a dict/namespace of all the non-default k,v arguments?
parser = argparse.ArgumentParser()
parser.add_argument("--a",type=str,default='a')
parser.add_argument("--b",type=str,default='b')
parser.add_argument("--c",type=str,default='c')
parser.add_argument("--d",type=str,default='d')
And
python run.py --a "e"
I would like to have
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--a",type=str,default='a')
parser.add_argument("--b",type=str,default='b')
parser.add_argument("--c",type=str,default='c')
parser.add_argument("--d",type=str,default='d')
non_default = parse_non_default(parser) # non_default = {'a':'e'}
You could lookup the parser and compare which values differenciate:
import argparse
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--a", type=str, default='a')
parser.add_argument("--b", type=str, default='b')
parser.add_argument("--c", type=str, default='c')
parser.add_argument("--d", type=str, default='d')
parser.add_argument("--n", type=int, default=999)
args = parser.parse_args(['--a', 'e']) # Test CLI arguments!
non_default = {
opt.dest: getattr(args, opt.dest)
for opt in parser._option_string_actions.values()
if hasattr(args, opt.dest) and opt.default != getattr(args, opt.dest)
}
print(non_default)
main()
Out:
{'a': 'e'}
import argparse
from queries import most_common_cities
parser = argparse.ArgumentParser(description='A script that does operations with database data and returns values')
parser.add_argument('-c', '--most_common_cities',
nargs=1,
type=positive_int,
help='Specify how many common cities.')
args = parser.parse_args()
if args.most_common_cities:
result = most_common_cities(n) # "n" should be an arg passed by user
print(result)
How could I pass arguments from CLI to my function arg?
When someone use command:
python argp.py --most_common_cities 5
It should return 5 most common cities.
Remove nargs=1, then args.most_common_cities will be the actual value passed in.
nargs=1 wraps it in a list.
parser.add_argument('-c', '--most_common_cities',
type=int,
help='Specify how many common cities.')
args = parser.parse_args(['-c', '5'])
n = args.most_common_cities
print(n)
print(type(n))
# 5
# <class 'int'>
I started your script with following command:
python3 test.py --most_common_cities 5
You can access the arguments with:
import argparse
parser = argparse.ArgumentParser(description='A script that does operations with database data and returns values')
parser.add_argument('-c', '--most_common_cities',
nargs=1,
type=int,
help='Specify how many common cities.')
args = parser.parse_args()
arguments = vars(parser.parse_args())
print(arguments) #{'most_common_cities': [5]}
#then you can access the value with:
arguments['most_common_cities']
I am trying to configure argparse so that only the following argument combinations are valid:
--flagA --argument1 val1 --argument2 val2 --argument3 val3
--flagB --argument1 val1
So far, I have written the following piece of code however it doesn't do the trick as both --argument2 and --argument3 are optional:
required_args = arg_parser.add_argument_group()
required_args.add_argument('--argument1', required=True)
# Optional arguments
optional_args = arg_parser.add_argument_group()
optional_args.add_argument('--argument2', required=False)
optional_args.add_argument('--argument3', required=False)
# Flags
flag_group = arg_parser.add_mutually_exclusive_group(required=True)
flag_group.add_argument('--flagA', dest='flag', action='store_const', const="flagA")
flag_group.add_argument('--flagB', dest='flag', action='store_const', const="flagB")
args = vars(arg_parser.parse_args())
With this setting, --flagA --argument1 val1 is also but it shouldn't be.
I know that I can process the Namespace generated after calling .parse_args() and check whether --argument2 and --argument3 are provided when --flagA is passed however I am looking for a more natural way to achieve this.
Essentially, the definition should look like the one below:
[-h] --argument1 ARGUMENT1 (--flagA --argument2 ARGUMENT2 --argument3 ARGUMENT3 | --flagB)
Have you considered using a subparser for the two flags?
something along the lines of
arg_parser = argparse.ArgumentParser()
subparser = arg_parser.add_subparsers(dest="flag", required=True)
flag_a = subparser.add_parser('flagA')
flag_a.add_argument('--argument1', required=True)
flag_a.add_argument('--argument2', required=True)
flag_a.add_argument('--argument3', required=True)
flag_b = subparser.add_parser('flagB')
flag_b.add_argument('--argument1', required=True)
Hope this helps
I have to invoke my script in this way.
script.py multiple --ways aa bb -as abab -bs bebe
In this case -as abab reffers to "aa" option from --ways parameter and -bs bebe to "bb" option.
And all chosed options should affect what "fulfill" method will be used.
If we chose 'aa' and 'bb' there should only be options '-as' and '-bs' not '-cs'.
import sys
from argparse import ArgumentParser
def fulfill_aa_parser(aa_parser):
aa_parser.add_argument('--ass', '-as', type=str, required=True, choices=['abababa'])
def fulfill_bb_parser(aa_parser):
aa_parser.add_argument('--bass', '-bs', type=str, required=True, choices=['bebebe'])
def fulfill_cc_parser(aa_parser):
aa_parser.add_argument('--cass', '-cs', type=str, required=True, choices=['cycycyc'])
def fulfill_multiple_parser(multiple_parser):
multiple_parser.add_argument('--ways', '-w', type=str, choices=['aa','bb', 'cc'], nargs='+', required=True)
def main(argv):
parser = ArgumentParser(description='TEST CASE')
subparsers = parser.add_subparsers(dest='type')
multiple_parser = subparsers.add_parser(
'multiple'
)
aabbparsers = multiple_parser.add_subparsers()
aa_parser = aabbparsers.add_parser('aa')
bb_parser = aabbparsers.add_parser('bb')
cc_parser = aabbparsers.add_parser('cc')
fulfill_multiple_parser(multiple_parser)
fulfill_aa_parser(aa_parser)
fulfill_bb_parser(bb_parser)
fulfill_cc_parser(cc_parser)
args = parser.parse_args(argv)
if args.type is None:
parser.print_help()
return
if __name__ == '__main__':
main(sys.argv[1:])
Parsing this in this way:
fulfill_aa_parser(multiple_parser)
fulfill_bb_parser(multiple_parser)
fulfill_cc_parser(multiple_parser)
will lead to parser always asking for '-as', '-bs' ,'-cs' and options in '--ways' will not affect this
EDIT : \
This is it looks when there is some thought put to it.
Just simply pass parser to this function
def fulfill_apple_argparser(parser):
parser.add_argument("--apple_argument")
def fulfill_banana_argparser(parser):
parser.add_argument("--banana_argument")
def fulfill_peach_argparser(parser):
parser.add_argument("--peach_argument")
def many_fruits_parse(parser, progs=None, list_of_fruits=('apple', 'banana', 'peach')):
progs = progs or []
if len(list_of_fruits) == 0 or parser in progs:
return
fulfill = {'apple': fulfill_apple_argparser, 'banana': fulfill_banana_argparser,
'peach': fulfill_peach_argparser}
subparsers = parser.add_subparsers(title='subparser', dest=parser.prog)
progs.append(parser)
for fruit in list_of_fruits:
secondary = [x for x in list_of_fruits if x != fruit]
fruit_parser = subparsers.add_parser(fruit, help=fruit)
fulfill[fruit](fruit_parser)
many_fruits_parse(fruit_parser, progs, secondary)
add_subparsers creates a special kind of positional argument, one that uses the add_parser command to create choices. Once a valid choice is provided, parsing is passed to that parser.
With
script.py multiple --ways aa bb -as abab -bs bebe
parser passes the task to multiple_parser. The --ways optional then gets 2 values
Namespace(ways=['aa','bb'])
Neither of those strings is used as a value for aabbparsers, and multiple_parser doesn't know what to do with '-as` or '-bs', and (I expect) will raise an error.
With:
script.py multiple aa -as abab
parsing is passed from parser to multiple_parser to aa_parser, which in turn handles '-as abab', producing (I think)
Namespace(as='abab')
Nesting as you do with multiple and aa is the only way to use multiple subparsers. You can't have two subparses 'in-parallel' (e.g. 'aa' and 'bb').
Especially when testing it's a good idea to provide a dest to the add_subparsers command. It gives information on which subparsers is being invoked.