I have a python script that I defined:
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--task', type=str)
parser.add_argument('--scale', type=int)
args = parser.parse_args()
... # Do things with my arguments
if __name__ == '__main__':
main()
And I call this script on command line doing:
python myscript.py --task mytask --scale 1
I would like to call this script in a jupyter notebook. Is there a way to do this parsing the arguments and not modifying my script at all? I.e., doing something that looks like to this:
import myscript
myscript.main(--task=mytask,scale=1)
P.S.: I tried using magic line such as %run (that probably could work in my case as well) but I had trouble collecting the returns of my script.
You can pass args to parser.parse_args:
# myscript.py
import argparse
def main(args=None):
parser = argparse.ArgumentParser()
parser.add_argument('--task', type=str)
parser.add_argument('--scale', type=int)
args = parser.parse_args(args=args)
print("task is: ", args.task)
print("scale is: ", args.scale)
if __name__ == "__main__":
main()
Output from cli:
python3 myscript.py --task aaa --scale 10
# task is: aaa
# scale is: 10
Output from python
import myscript
myscript.main("--task aaa --scale 10".split())
# task is: aaa
# scale is: 10
Related
This is probably a silly question but I've been struggling with this for a while now and I could not make it work. Basically what I am trying to do is use a script output with the command line passed arguments as an input for another script with arguments as well. This is my approach so far, I kind of feel that I am missing something though.
Let's suppose the following script1.py
# !/usr/bin/env python3
import argparse
import sys
def create_arg_parser():
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--number", type=int, help="numbers range")
return parser.parse_args()
def main_a():
nrange = parsed_args.number
l = [i for i in range(nrange)]
return l
if __name__ == "__main__":
parsed_args = create_arg_parser()
print(main_a())
and script2.py
# !/usr/bin/env python3
import os
import subprocess
import argparse
def create_arg_parser():
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--outdir", type=str, help="outdir path")
return parser.parse_args()
def main_b():
# the -n argument here should be inherited from script1.py and not manually set to 5
process = subprocess.Popen(["python", "script1.py", "-n", "5"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = process.communicate() # let it run the list from script1.py
with open(os.path.join(parsed_args.outdir, "list.txt"), "w") as f:
f.write(output[0].decode('utf-8'))
if __name__ == "__main__":
parsed_args = create_arg_parser()
main_b()
This actually works (kinda actually), apart from the fact that I am getting the list outputted from script1.py written alongside the -n argument. What I am trying to do here is use the list created from script1.py as input in script2.py, but just passing the command line arguments once. So for instance, use or inherit the arguments used for script1.py in script2.py. I know this could be done putting all in the same script but this is just an example, I am trying to write a *gml graph in the real problem.
Any idea what I am missing here? Or is there any workaround or a simpler alternative to my approach?
While you can inherit arguments from another parser, for your use case it would be simpler to just define an argument explicitly, since you have to pass the value that results to the other script.
# !/usr/bin/env python3
import os
import subprocess
import argparse
def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--number", type=int, help="numbers range")
parser.add_argument("-o", "--outdir", type=str, help="outdir path")
return parser.parse_args()
def main_b(args):
# the -n argument here should be inherited from script1.py and not manually set to 5
process = subprocess.Popen(["python", "script1.py", "-n", args.number], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = process.communicate() # let it run the list from script1.py
with open(os.path.join(parsed_args.outdir, "list.txt"), "w") as f:
f.write(output[0].decode('utf-8'))
if __name__ == "__main__":
parsed_args = parse_arguments()
main_b(parsed_args)
The alternative is that your first script has to expose its argument parser as a module-level attribute, and your second script would have to import the first. (That would, however, bypass the need to use subprocess to run the first script.
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--number", type=int, help="numbers range")
def main_a(n):
l = [i for i in range(n)]
return l
if __name__ == "__main__":
nrange = parser.parse_args().number
print(main_a(nrange))
and
import os
import argparse
import script1
def parse_arguments():
parser = argparse.ArgumentParser(parents=[script1.parser])
parser.add_argument("-o", "--outdir", type=str, help="outdir path")
return parser.parse_args()
def main_b(parsed_args):
x = script1.main_a(parsed_args.number)
with open(os.path.join(parsed_args.outdir, "list.txt"), "w") as f:
f.write(str(x))
if __name__ == "__main__":
parsed_args = parse_arguments()
main_b(parsed_args)
I have this code:
#!flask/bin/python
import subprocess
import types
from flask import Flask, jsonify, make_response, abort, request, url_for
app = Flask(__name__)
#app.route('/v1/kill/process/<processName>')
def killProcess(processName):
pid = subprocess.Popen(["pidof", processName], stdout=subprocess.PIPE)
pid = pid.stdout.read()
if len(pid) != 0:
for p in pid.decode("utf-8").split(" "):
p = int(p)
subprocess.call(["kill","-9", str(p)])
return make_response(jsonify({'error': False}), 200)
else:
return make_response(jsonify({'error': "Service Not Found"}), 400)
if __name__ == '__main__':
app.run(debug=True, port=8888)
I want to run this code like this:
python fileName.py --port 8888,
How to send --port argument to python and port not hard code.
There are many problems in your script. But i'm just gonna answer your question.
The argparse module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and argparse will figure out how to parse those out of sys.argv. The argparse module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.
Python argparse
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Description of your program')
parser.add_argument('-p','--port', help='Port_number', required=True)
args = vars(parser.parse_args())
app.run(debug=True, port=args['port'])
args['port'] is a string
When Python runs the arguments are passed in as the array sys.argv.
You can do this in one of two ways. You can use the built-in argparse module, or you can directly access the sys.argv.
Using argparse:
import argparse
parser = argparse.ArgumentParser(description='Run flask program')
parser.add_argument(
'--port',
action='store',
dest='port',
type=int,
default=8888,
metavar='PORTNUM',
help='set port number')
args = parser.parse_args()
print(args.port)
Using the sys.argv directly:
import os
import sys
port = 8888 # default value
reversed_args = list(reversed(sys.argv[1:]))
while True:
if not len(reversed_args):
break
if reversed_args[-1] == '--port':
reversed_args.pop()
if not len(args):
sys.exit(127)
path = int(reversed_args.pop())
else:
sys.exit(127)
print(port)
When i import one of my python scripts and run my current script , it seems to be running and displaying the output of the imported script which is really unusual behaviour. I have just imported this in my script but not really called any of its functions in my main code. How can i avoid from this behaviour happening ?
If i pass the -d flag with my main script it will run the usual code in my main script only
If i pass the -t flag with my main script , it will run the code from the imported python script only
main.py
import os
import argparse
import functions as funcs
import generate_json as gen_json
from test_compare_filesets import tester as imptd_tester
def get_json_location():
path = os.getcwd() + '/Testdata'
return path
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--export-date", action="store_true", required=True)
parser.add_argument("-t", "--execute-test", action="store_true", required=False)
args = parser.parse_args()
date = args.export_date
testt = args.execute_test
yml_directory = os.listdir('yaml/')
yml_directory.remove('export_config.yaml')
with open('dates/' + date + '.json', 'w') as start:
start.close()
for yml in yml_directory :
print("Running export for " + yml)
yml_file = os.path.join('yaml/' + yml)
json_path = get_json_location()
yml = funcs.read_config(yml_file)
data_folder = date
gen_json.generate_data_report(json_path , yml , data_folder)
if __name__ == '__main__':
main()
test_files.py
import generate_report as generate_reportt
def compare_filesets(file_names, previous_data, current_data):
for item in file_names:
print(item + generate_reportt.compare(previous_data.get(item), current_data.get(item)) + "\n")
def test_filesets():
'''
Test for scenario 1
'''
dict_1 = generate_reportt.read_file_into_dict("dates/2018-01-01.json")
dict_2 = generate_reportt.read_file_into_dict("dates/2018-01-02.json")
print(" Test 1 ")
compare_filesets(file_names=['a.json', 'b.json', 'c.json'],
previous_data=dict_1,
current_data=dict_2
)
This is why using the statement:
if __name__ == "__main__":
main()
is very important. You will want to add this to the script you're importing, and put all of your code that is being called within a main() function in that script. The variable __name__ of a script changes depending on whether the script is imported or not. If you're not importing the script and running it, then that script's __name__ variable will be "__main__". However, if it is imported, the __name__ variable turns into the script's filename, and therefore everything in main() function of that script will not be run.
For more information: What does if __name__ == "__main__": do?
i'm trying to make my python program interactive in command line, user should be able to do stuff like :
python myprogram.py --create
then
python myprogram.py --send
The problem in this when is that the program stop and restart each time so i lose my variable and object that i created with the first command.
I'm using argparse on this way:
parser = argparse.ArgumentParser()
parser.add_argument('-c','--create' ,help='',action='store_true')
parser.add_argument('-s','--send',help='',action='store_true')
args = parser.parse_args()
if args.create:
create()
elif args.send :
send()
I don't want to stop the program between the command, how to do this ?
example : https://coderwall.com/p/w78iva
Here's a simple interactive script. I use argparse to parse the input lines, but otherwise it is not essential to the action. Still it can be an handy way of adding options to your 'create' command. For example, ipython uses argparse to handle its %magic commands:
import argparse
parser = argparse.ArgumentParser(prog='PROG', description='description')
parser.add_argument('cmd', choices=['create','delete','help','quit'])
while True:
astr = raw_input('$: ')
# print astr
try:
args = parser.parse_args(astr.split())
except SystemExit:
# trap argparse error message
print 'error'
continue
if args.cmd in ['create', 'delete']:
print 'doing', args.cmd
elif args.cmd == 'help':
parser.print_help()
else:
print 'done'
break
This could be stripped down to the while loop, the raw_input line, and your own evaluation of the astr variable.
The keys to using argparse here are:
parse_args can take a list of strings (the result of split()) instead of using the default sys.argv[1:].
if parse_args sees a problem (or '-h') it prints a message and tries to 'exit'. If you want to continue, you need to trap that error, hence the try block.
the output of parse_args is a simple namespace object. You access the arguments as attributes.
you could easily substitute your own parser.
The diffrence in cmd and argparse is that cmd is a "line-oriented command interpreter" while argparse is a parser for sys.argv.
Your example parses sys.argv that you pass while running your program and then if it gets the value you start a function and then quits.
argparse will only parse the sys.argv while running the program.
You could add some code to be able to work with the args you pass like a function or class or make in program menu that you could operate with raw_input.
Example:
class Main():
def __init__(self, create=None, send=None):
if create:
self.create(create)
elif send:
self.send(send)
option = raw_input('What do you want to do now?')
print option
def create(self, val):
print val
def send(self, val):
print val
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-c','--create' ,help='',action='store_true')
parser.add_argument('-s','--send',help='',action='store_true')
args = parser.parse_args()
Main(args.create, args.send)
Other then that Python argparse and controlling/overriding the exit status code or python argparse - add action to subparser with no arguments? might help.
In the first it shows how you can override the quit and in the second how can you add subcommands or quitactions.
I cannot get ArgumentParser to work. What's wrong with the following:
import argparse
parser=argparse.ArgumentParser(description='''I wish this description would output''',
epilog='''Please out the epilog''')
parser.add_argument('-l', type=str, default='info', help='logging level. Default is info. Use debug if you have problems.')
args=parser.parse_args()
def main():
print("goodbye")
if __name__ == "__main__":
#main
main()
When I run myscript -h I see no help.
I am running Python 2.7 on Windows 7. I have Python on my path and also pathext set as:
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.py
The argsparse code never actually gets executed. By executing the script from the command line, you're calling main(), which simply prints and exits. You have to call parse_args() in the main() function for this to work.
import argparse
# Personally, I think these belong in the main()
# function as well, but they don't need to be.
parser = argparse.ArgumentParser(
description="I wish this description would output",
epilog="Please out the epilog"
)
parser.add_argument(
"-l",
type=str,
default="info",
help="logging level. Default is info. Use debug if you have problems."
)
def main():
args = parser.parse_args() # Parses arguments
print("goodbye")
if __name__ == "__main__":
main() # Calls main
Produces:
~/Desktop $ python untitled.py --help
usage: untitled.py [-h] [-l L]
I wish this description would output
optional arguments:
-h, --help show this help message and exit
-l L logging level. Default is info. Use debug if you have problems.
Please out the epilog
jcollado claims your code worked fine on Ubuntu--I find this very curious.
If you run this script from the command line you're going to just print 'goodbye', put the argparse code after if __name__ == "__main__":.
OK weird answer for this. The problem was resolved by calling the program as:
python myscript.py -h
If you add python to your path, set file associations and then just do:
myscript.py -h
it will not pick up the -h